From 18f09f9862986e6ed3f10d336c7d0e89855d47df Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 15 May 2018 00:08:23 +0100 Subject: [PATCH] Various performance optimizations --- .../bukkit/BukkitSchedulerAdapter.java | 145 +----------------- .../luckperms/bukkit/BukkitSenderFactory.java | 2 +- .../luckperms/bukkit/LPBukkitPlugin.java | 26 ++-- .../calculators/BukkitCalculatorFactory.java | 6 +- .../listeners/BukkitConnectionListener.java | 2 +- .../bukkit/messaging/LilyPadMessenger.java | 2 +- .../permissible/LPPermissionAttachment.java | 1 - .../bukkit/model/server/LPDefaultsMap.java | 95 +++++------- .../bungee/BungeeSchedulerAdapter.java | 82 ++-------- .../luckperms/bungee/LPBungeeBootstrap.java | 2 +- .../luckperms/bungee/LPBungeePlugin.java | 9 +- .../calculators/BungeeCalculatorFactory.java | 6 +- .../listeners/BungeeConnectionListener.java | 4 +- .../bungee/messaging/BungeeMessenger.java | 2 +- .../AbstractCalculatorFactory.java | 47 ------ .../commands/generic/parent/ParentInfo.java | 3 +- .../generic/permission/PermissionInfo.java | 3 +- .../common/commands/log/LogNotify.java | 5 +- .../common/commands/misc/ExportCommand.java | 2 +- .../common/commands/misc/ImportCommand.java | 2 +- .../common/config/AbstractConfiguration.java | 107 +++++++------ .../BaseConfigKey.java} | 20 +-- .../luckperms/common/config/ConfigKey.java | 10 ++ .../luckperms/common/config/ConfigKeys.java | 55 ++++--- .../common/config/LuckPermsConfiguration.java | 4 +- .../common/config/keys/BooleanKey.java | 4 +- .../keys/{AbstractKey.java => CustomKey.java} | 10 +- .../common/config/keys/EnduringKey.java | 3 +- .../common/config/keys/IntegerKey.java | 4 +- .../config/keys/LowercaseStringKey.java | 4 +- .../luckperms/common/config/keys/MapKey.java | 4 +- .../common/config/keys/StringKey.java | 4 +- .../common/event/AbstractEventBus.java | 2 +- .../inheritance/InheritanceHandler.java | 25 +-- .../managers/user/AbstractUserManager.java | 3 +- .../messaging/LuckPermsMessagingService.java | 6 +- .../messaging/redis/RedisMessenger.java | 2 +- .../common/messaging/sql/SqlMessenger.java | 7 +- .../node/comparator/NodeComparator.java | 3 +- .../comparator/NodeWithContextComparator.java | 37 ++--- .../common/node/model/ForwardingNode.java | 2 +- .../node/model/ImmutableLocalizedNode.java | 2 +- .../common/node/model/ImmutableNode.java | 1 - .../node/model/ImmutableTransientNode.java | 2 +- .../plugin/AbstractLuckPermsPlugin.java | 23 ++- .../plugin/bootstrap/LuckPermsBootstrap.java | 2 +- .../scheduler/AbstractJavaScheduler.java | 98 ++++++++++++ .../{ => scheduler}/SchedulerAdapter.java | 61 ++++---- .../common/storage/dao/file/FileWatcher.java | 4 +- .../common/treeview/PermissionRegistry.java | 5 +- .../common/utils/CollationKeyCache.java | 88 ----------- .../luckperms/common/utils/ExpiringSet.java | 10 +- .../luckperms/common/utils/PatternCache.java | 4 +- .../luckperms/common/utils/RepeatingTask.java | 21 +-- .../common/verbose/VerboseHandler.java | 5 +- .../luckperms/nukkit/LPNukkitPlugin.java | 24 +-- .../nukkit/NukkitSchedulerAdapter.java | 145 +----------------- .../luckperms/nukkit/NukkitSenderFactory.java | 2 +- .../calculators/NukkitCalculatorFactory.java | 6 +- .../listeners/NukkitConnectionListener.java | 2 +- .../nukkit/model/server/LPDefaultsMap.java | 91 ++++++----- .../sponge/service/CompatibilityUtil.java | 24 +-- .../reference/SubjectReferenceFactory.java | 7 +- .../luckperms/sponge/LPSpongeBootstrap.java | 2 +- .../luckperms/sponge/LPSpongePlugin.java | 11 +- .../sponge/SpongeSchedulerAdapter.java | 79 +++------- .../calculators/SpongeCalculatorFactory.java | 6 +- .../listeners/SpongeConnectionListener.java | 2 +- .../sponge/service/LuckPermsService.java | 2 - .../service/event/UpdateEventHandlerImpl.java | 2 +- .../service/internal/HolderSubject.java | 2 +- .../persisted/SubjectDataContainer.java | 5 +- 72 files changed, 533 insertions(+), 967 deletions(-) delete mode 100644 common/src/main/java/me/lucko/luckperms/common/calculators/AbstractCalculatorFactory.java rename common/src/main/java/me/lucko/luckperms/common/{calculators/PlatformCalculatorFactory.java => config/BaseConfigKey.java} (77%) rename common/src/main/java/me/lucko/luckperms/common/config/keys/{AbstractKey.java => CustomKey.java} (84%) create mode 100644 common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/AbstractJavaScheduler.java rename common/src/main/java/me/lucko/luckperms/common/plugin/{ => scheduler}/SchedulerAdapter.java (58%) delete mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/CollationKeyCache.java 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 d260ad97..eddb3f63 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSchedulerAdapter.java @@ -25,95 +25,16 @@ package me.lucko.luckperms.bukkit; -import com.google.common.util.concurrent.ThreadFactoryBuilder; +import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; -import me.lucko.luckperms.common.plugin.SchedulerTask; -import me.lucko.luckperms.common.utils.Iterators; - -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; - -public class BukkitSchedulerAdapter implements SchedulerAdapter { - private final LPBukkitBootstrap bootstrap; - - private final ExecutorService asyncFallback; - private final Executor asyncBukkit; +public class BukkitSchedulerAdapter extends AbstractJavaScheduler implements SchedulerAdapter { private final Executor sync; - private final Executor async; - - private boolean useFallback = true; - - private final Set tasks = ConcurrentHashMap.newKeySet(); public BukkitSchedulerAdapter(LPBukkitBootstrap bootstrap) { - this.bootstrap = bootstrap; - - this.sync = new SyncExecutor(); - this.asyncFallback = new FallbackAsyncExecutor(); - this.asyncBukkit = new BukkitAsyncExecutor(); - this.async = new AsyncExecutor(); - } - - private BukkitScheduler scheduler() { - return this.bootstrap.getServer().getScheduler(); - } - - @Override - public void doAsync(Runnable runnable) { - async().execute(runnable); - } - - @Override - public void doSync(Runnable runnable) { - sync().execute(runnable); - } - - @Override - public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) { - SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimerAsynchronously(this.bootstrap, runnable, intervalTicks, intervalTicks)); - this.tasks.add(task); - return task; - } - - @Override - public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) { - SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimer(this.bootstrap, runnable, intervalTicks, intervalTicks)); - this.tasks.add(task); - return task; - } - - @Override - public SchedulerTask asyncLater(Runnable runnable, long delayTicks) { - return new BukkitSchedulerTask(scheduler().runTaskLaterAsynchronously(this.bootstrap, runnable, delayTicks)); - } - - @Override - public SchedulerTask syncLater(Runnable runnable, long delayTicks) { - return new BukkitSchedulerTask(scheduler().runTaskLater(this.bootstrap, runnable, delayTicks)); - } - - @Override - public void shutdown() { - Iterators.iterate(this.tasks, SchedulerTask::cancel); - - // wait for executor - this.asyncFallback.shutdown(); - try { - this.asyncFallback.awaitTermination(30, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + this.sync = r -> bootstrap.getServer().getScheduler().scheduleSyncDelayedTask(bootstrap, r); } @Override @@ -121,62 +42,4 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter { return this.sync; } - @Override - public Executor async() { - return this.async; - } - - @Override - public Executor platformAsync() { - return this.asyncBukkit; - } - - public void setUseFallback(boolean useFallback) { - this.useFallback = useFallback; - } - - private final class SyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleSyncDelayedTask(BukkitSchedulerAdapter.this.bootstrap, runnable); - } - } - - private final class AsyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - if (BukkitSchedulerAdapter.this.useFallback || !BukkitSchedulerAdapter.this.bootstrap.isEnabled()) { - BukkitSchedulerAdapter.this.asyncFallback.execute(runnable); - } else { - BukkitSchedulerAdapter.this.asyncBukkit.execute(runnable); - } - } - } - - private final class BukkitAsyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().runTaskAsynchronously(BukkitSchedulerAdapter.this.bootstrap, runnable); - } - } - - 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()); - } - } - - private static final class BukkitSchedulerTask implements SchedulerTask { - private final BukkitTask task; - - private BukkitSchedulerTask(BukkitTask task) { - this.task = task; - } - - @Override - public void cancel() { - this.task.cancel(); - } - } - } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java index 3d863fcb..c3177357 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java @@ -79,7 +79,7 @@ public class BukkitSenderFactory extends SenderFactory { } // otherwise, send the message sync - getPlugin().getBootstrap().getScheduler().doSync(new SyncMessengerAgent(sender, s)); + getPlugin().getBootstrap().getScheduler().executeSync(new SyncMessengerAgent(sender, s)); } @Override 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 7016ccb8..c4f1b294 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -46,7 +46,7 @@ import me.lucko.luckperms.bukkit.model.server.LPSubscriptionMap; import me.lucko.luckperms.bukkit.vault.VaultHookManager; import me.lucko.luckperms.common.api.LuckPermsApiProvider; import me.lucko.luckperms.common.api.delegates.model.ApiUser; -import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.command.access.CommandPermission; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; @@ -78,6 +78,7 @@ import java.util.EnumSet; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -152,7 +153,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { } @Override - protected PlatformCalculatorFactory provideCalculatorFactory() { + protected CalculatorFactory provideCalculatorFactory() { return new BukkitCalculatorFactory(this); } @@ -177,7 +178,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { // schedule another injection after all plugins have loaded // the entire pluginmanager instance is replaced by some plugins :( - this.bootstrap.getScheduler().asyncLater(injector, 1L); + this.bootstrap.getServer().getScheduler().runTaskLaterAsynchronously(this.bootstrap, injector, 1); } // Provide vault support @@ -214,8 +215,8 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { @Override protected void registerHousekeepingTasks() { - this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L); - this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L); + this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS); + this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES); } @Override @@ -234,7 +235,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { // remove all operators on startup if they're disabled if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) { - this.bootstrap.getScheduler().platformAsync().execute(() -> { + this.bootstrap.getServer().getScheduler().runTaskAsynchronously(this.bootstrap, () -> { for (OfflinePlayer player : this.bootstrap.getServer().getOperators()) { player.setOp(false); } @@ -250,16 +251,13 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { }); } - // replace the temporary executor when the Bukkit one starts - this.bootstrap.getServer().getScheduler().runTaskAsynchronously(this.bootstrap, () -> this.bootstrap.getScheduler().setUseFallback(false)); - // Load any online users (in the case of a reload) for (Player player : this.bootstrap.getServer().getOnlinePlayers()) { - this.bootstrap.getScheduler().doAsync(() -> { + this.bootstrap.getScheduler().executeAsync(() -> { try { User user = this.connectionListener.loadUser(player.getUniqueId(), player.getName()); if (user != null) { - this.bootstrap.getScheduler().doSync(() -> { + this.bootstrap.getScheduler().executeSync(() -> { try { LPPermissible lpPermissible = new LPPermissible(player, user, this); PermissibleInjector.inject(player, lpPermissible); @@ -275,12 +273,6 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { } } - @Override - protected void performEarlyDisableTasks() { - // Switch back to the fallback executor, the bukkit one won't allow new tasks - this.bootstrap.getScheduler().setUseFallback(true); - } - @Override protected void removePlatformHooks() { // uninject from players diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java index 55e3ef2a..02d88e2d 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java @@ -32,7 +32,7 @@ import me.lucko.luckperms.api.LookupSetting; import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.bukkit.processors.ChildProcessor; import me.lucko.luckperms.bukkit.processors.DefaultsProcessor; -import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.calculators.PermissionCalculator; import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata; import me.lucko.luckperms.common.config.ConfigKeys; @@ -42,7 +42,7 @@ import me.lucko.luckperms.common.processors.PermissionProcessor; import me.lucko.luckperms.common.processors.RegexProcessor; import me.lucko.luckperms.common.processors.WildcardProcessor; -public class BukkitCalculatorFactory extends AbstractCalculatorFactory { +public class BukkitCalculatorFactory implements CalculatorFactory { private final LPBukkitPlugin plugin; public BukkitCalculatorFactory(LPBukkitPlugin plugin) { @@ -71,6 +71,6 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory { processors.add(new DefaultsProcessor(this.plugin, contexts.hasSetting(LookupSetting.IS_OP))); } - return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); + return new PermissionCalculator(this.plugin, metadata, processors.build()); } } 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 a8cd0cf2..8fae5b91 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 @@ -191,7 +191,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId()); // force a clear of transient nodes - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId()); if (user != null) { user.clearTransientNodes(); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java index ba6632c4..9b10ea47 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/messaging/LilyPadMessenger.java @@ -87,7 +87,7 @@ public class LilyPadMessenger implements Messenger { @EventListener public void onMessage(MessageEvent event) { - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { try { String channel = event.getChannel(); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java index 45fe09d8..403b4eac 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java @@ -189,7 +189,6 @@ public class LPPermissionAttachment extends PermissionAttachment { // remove transient permissions from the holder which were added by this attachment & equal the permission User user = this.permissible.getUser(); - user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java index 8654adba..993f8571 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java @@ -33,6 +33,7 @@ import com.google.common.collect.Maps; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.bukkit.LPBukkitPlugin; +import me.lucko.luckperms.common.buffers.Cache; import org.bukkit.permissions.Permission; import org.bukkit.plugin.PluginManager; @@ -67,8 +68,8 @@ public final class LPDefaultsMap implements Map> { private final Set nonOpSet = new DefaultPermissionSet(false); // fully resolved defaults (accounts for child permissions too) - private Map resolvedOpDefaults = ImmutableMap.of(); - private Map resolvedNonOpDefaults = ImmutableMap.of(); + private DefaultsCache opCache = new DefaultsCache(true); + private DefaultsCache nonOpCache = new DefaultsCache(false); // #values and #entrySet results - both immutable private final Collection> values = ImmutableList.of(this.opSet, this.nonOpSet); @@ -81,16 +82,20 @@ public final class LPDefaultsMap implements Map> { this.plugin = plugin; this.opSet.addAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptySet())); this.nonOpSet.addAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptySet())); - refreshOp(); - refreshNonOp(); } - public Set getOpPermissions() { - return this.opSet; + @Override + public Set get(Object key) { + boolean b = (boolean) key; + return b ? this.opSet : this.nonOpSet; } - public Set getNonOpPermissions() { - return this.nonOpSet; + private DefaultsCache getCache(boolean op) { + return op ? this.opCache : this.nonOpCache; + } + + private void invalidate(boolean op) { + getCache(op).invalidate(); } /** @@ -101,54 +106,10 @@ public final class LPDefaultsMap implements Map> { * @return a tristate result */ public Tristate lookupDefaultPermission(String permission, boolean isOp) { - Map map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults; + Map map = getCache(isOp).get(); return Tristate.fromNullableBoolean(map.get(permission)); } - private void refresh(boolean op) { - if (op) { - refreshOp(); - } else { - refreshNonOp(); - } - } - - /** - * Refreshes the op data in this provider. - */ - private void refreshOp() { - Map builder = new HashMap<>(); - for (Permission perm : getOpPermissions()) { - String name = perm.getName().toLowerCase(); - builder.put(name, true); - for (Map.Entry child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { - builder.putIfAbsent(child.getKey(), child.getValue()); - } - } - this.resolvedOpDefaults = ImmutableMap.copyOf(builder); - } - - /** - * Refreshes the non op data in this provider. - */ - private void refreshNonOp() { - Map builder = new HashMap<>(); - for (Permission perm : getNonOpPermissions()) { - String name = perm.getName().toLowerCase(); - builder.put(name, true); - for (Map.Entry child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { - builder.putIfAbsent(child.getKey(), child.getValue()); - } - } - this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder); - } - - @Override - public Set get(Object key) { - boolean b = (boolean) key; - return b ? this.opSet : this.nonOpSet; - } - // return wrappers around this map impl @Nonnull @Override public Collection> values() { return this.values; } @Nonnull @Override public Set>> entrySet() { return this.entrySet; } @@ -166,11 +127,33 @@ public final class LPDefaultsMap implements Map> { @Override public void putAll(@Nonnull Map> m) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } + private final class DefaultsCache extends Cache> { + private final boolean op; + + DefaultsCache(boolean op) { + this.op = op; + } + + @Nonnull + @Override + protected Map supply() { + Map builder = new HashMap<>(); + for (Permission perm : LPDefaultsMap.this.get(this.op)) { + String name = perm.getName().toLowerCase(); + builder.put(name, true); + for (Map.Entry child : LPDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { + builder.putIfAbsent(child.getKey(), child.getValue()); + } + } + return ImmutableMap.copyOf(builder); + } + } + private final class DefaultPermissionSet extends ForwardingSet { private final Set delegate = ConcurrentHashMap.newKeySet(); private final boolean op; - private DefaultPermissionSet(boolean op) { + DefaultPermissionSet(boolean op) { this.op = op; } @@ -182,14 +165,14 @@ public final class LPDefaultsMap implements Map> { @Override public boolean add(@Nonnull Permission element) { boolean ret = super.add(element); - refresh(this.op); + invalidate(this.op); return ret; } @Override public boolean addAll(@Nonnull Collection collection) { boolean ret = super.addAll(collection); - refresh(this.op); + invalidate(this.op); return ret; } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSchedulerAdapter.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSchedulerAdapter.java index f419b718..0289ea78 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSchedulerAdapter.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSchedulerAdapter.java @@ -25,104 +25,56 @@ package me.lucko.luckperms.bungee; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.plugin.SchedulerTask; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.utils.Iterators; import net.md_5.bungee.api.scheduler.ScheduledTask; -import net.md_5.bungee.api.scheduler.TaskScheduler; +import java.util.Collections; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.WeakHashMap; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; public class BungeeSchedulerAdapter implements SchedulerAdapter { - - // the number of ticks which occur in a second - this is a server implementation detail - public static final int TICKS_PER_SECOND = 20; - // the number of milliseconds in a second - constant - public static final int MILLISECONDS_PER_SECOND = 1000; - // the number of milliseconds in a tick - assuming the server runs at a perfect tick rate - public static final int MILLISECONDS_PER_TICK = MILLISECONDS_PER_SECOND / TICKS_PER_SECOND; - - private static long ticksToMillis(long ticks) { - return ticks * MILLISECONDS_PER_TICK; - } - private final LPBungeeBootstrap bootstrap; - private final Executor asyncExecutor; - private final Set tasks = ConcurrentHashMap.newKeySet(); + private final Executor executor; + private final Set tasks = Collections.newSetFromMap(new WeakHashMap<>()); public BungeeSchedulerAdapter(LPBungeeBootstrap bootstrap) { this.bootstrap = bootstrap; - this.asyncExecutor = r -> bootstrap.getProxy().getScheduler().runAsync(bootstrap, r); - } - - private TaskScheduler scheduler() { - return this.bootstrap.getProxy().getScheduler(); + this.executor = r -> bootstrap.getProxy().getScheduler().runAsync(bootstrap, r); } @Override public Executor async() { - return this.asyncExecutor; + return this.executor; } @Override public Executor sync() { - return this.asyncExecutor; + return this.executor; } @Override - public void doAsync(Runnable runnable) { - this.asyncExecutor.execute(runnable); + public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) { + ScheduledTask t = this.bootstrap.getProxy().getScheduler().schedule(this.bootstrap, task, delay, unit); + this.tasks.add(t); + return t::cancel; } @Override - public void doSync(Runnable runnable) { - doAsync(runnable); - } - - @Override - public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) { - long millis = ticksToMillis(intervalTicks); - SchedulerTask task = new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, millis, millis, TimeUnit.MILLISECONDS)); - this.tasks.add(task); - return task; - } - - @Override - public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) { - return asyncRepeating(runnable, intervalTicks); - } - - @Override - public SchedulerTask asyncLater(Runnable runnable, long delayTicks) { - return new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, ticksToMillis(delayTicks), TimeUnit.MILLISECONDS)); - } - - @Override - public SchedulerTask syncLater(Runnable runnable, long delayTicks) { - return asyncLater(runnable, delayTicks); + public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) { + ScheduledTask t = this.bootstrap.getProxy().getScheduler().schedule(this.bootstrap, task, interval, interval, unit); + this.tasks.add(t); + return t::cancel; } @Override public void shutdown() { - Iterators.iterate(this.tasks, SchedulerTask::cancel); - } - - private static final class BungeeSchedulerTask implements SchedulerTask { - private final ScheduledTask task; - - private BungeeSchedulerTask(ScheduledTask task) { - this.task = task; - } - - @Override - public void cancel() { - this.task.cancel(); - } + Iterators.iterate(this.tasks, ScheduledTask::cancel); } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeeBootstrap.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeeBootstrap.java index 7c0fe1e0..20f48417 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeeBootstrap.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeeBootstrap.java @@ -29,8 +29,8 @@ import me.lucko.luckperms.api.platform.PlatformType; import me.lucko.luckperms.bungee.util.RedisBungeeUtil; import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader; import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index f1d42c74..a710aa20 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -35,7 +35,7 @@ import me.lucko.luckperms.bungee.listeners.BungeeConnectionListener; import me.lucko.luckperms.bungee.listeners.BungeePermissionCheckListener; import me.lucko.luckperms.bungee.messaging.BungeeMessagingFactory; import me.lucko.luckperms.common.api.LuckPermsApiProvider; -import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; import me.lucko.luckperms.common.contexts.ContextManager; @@ -61,6 +61,7 @@ import java.nio.file.Files; import java.util.EnumSet; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -130,7 +131,7 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin { } @Override - protected PlatformCalculatorFactory provideCalculatorFactory() { + protected CalculatorFactory provideCalculatorFactory() { return new BungeeCalculatorFactory(this); } @@ -161,8 +162,8 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin { @Override protected void registerHousekeepingTasks() { - this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L); - this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L); + this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS); + this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES); } @Override diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java b/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java index 11628bbd..dde4894a 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java @@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.bungee.LPBungeePlugin; -import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.calculators.PermissionCalculator; import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata; import me.lucko.luckperms.common.config.ConfigKeys; @@ -38,7 +38,7 @@ import me.lucko.luckperms.common.processors.PermissionProcessor; import me.lucko.luckperms.common.processors.RegexProcessor; import me.lucko.luckperms.common.processors.WildcardProcessor; -public class BungeeCalculatorFactory extends AbstractCalculatorFactory { +public class BungeeCalculatorFactory implements CalculatorFactory { private final LPBungeePlugin plugin; public BungeeCalculatorFactory(LPBungeePlugin plugin) { @@ -59,6 +59,6 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory { processors.add(new WildcardProcessor()); } - return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); + return new PermissionCalculator(this.plugin, metadata, processors.build()); } } 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 b9ac65b4..1e6e8582 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 @@ -70,7 +70,7 @@ public class BungeeConnectionListener extends AbstractConnectionListener impleme this.plugin.getLogger().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName()); } - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { recordConnection(c.getUniqueId()); /* Actually process the login for the connection. @@ -139,7 +139,7 @@ public class BungeeConnectionListener extends AbstractConnectionListener impleme this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId()); // force a clear of transient nodes - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId()); if (user != null) { user.clearTransientNodes(); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java index b135b26a..2ee59941 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/messaging/BungeeMessenger.java @@ -97,7 +97,7 @@ public class BungeeMessenger implements Messenger, Listener { if (this.consumer.consumeIncomingMessageAsString(msg)) { // Forward to other servers - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { for (ServerInfo server : this.plugin.getBootstrap().getProxy().getServers().values()) { server.sendData(CHANNEL, data, true); } diff --git a/common/src/main/java/me/lucko/luckperms/common/calculators/AbstractCalculatorFactory.java b/common/src/main/java/me/lucko/luckperms/common/calculators/AbstractCalculatorFactory.java deleted file mode 100644 index 854cbac1..00000000 --- a/common/src/main/java/me/lucko/luckperms/common/calculators/AbstractCalculatorFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.calculators; - -import com.google.common.collect.MapMaker; - -import java.util.Collections; -import java.util.Set; - -public abstract class AbstractCalculatorFactory implements PlatformCalculatorFactory { - private final Set calculators = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); - - protected PermissionCalculator registerCalculator(PermissionCalculator calculator) { - this.calculators.add(calculator); - return calculator; - } - - @Override - public void invalidateAll() { - for (PermissionCalculator calculator : this.calculators) { - calculator.invalidateCache(); - } - } -} diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java index 11cf6bef..ff53fb28 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentInfo.java @@ -44,7 +44,6 @@ import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator; import me.lucko.luckperms.common.node.factory.NodeFactory; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; -import me.lucko.luckperms.common.utils.CollationKeyCache; import me.lucko.luckperms.common.utils.DurationFormatter; import me.lucko.luckperms.common.utils.Iterators; import me.lucko.luckperms.common.utils.Predicates; @@ -126,7 +125,7 @@ public class ParentInfo extends SharedSubCommand { } private static final Comparator ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> { - int i = CollationKeyCache.compareStrings(o1.getGroupName(), o2.getGroupName()); + int i = o1.getGroupName().compareTo(o2.getGroupName()); if (i != 0) { return i; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java index e9410f6f..3cd151c4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionInfo.java @@ -44,7 +44,6 @@ import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator; import me.lucko.luckperms.common.node.factory.NodeFactory; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; -import me.lucko.luckperms.common.utils.CollationKeyCache; import me.lucko.luckperms.common.utils.DurationFormatter; import me.lucko.luckperms.common.utils.Iterators; import me.lucko.luckperms.common.utils.Predicates; @@ -129,7 +128,7 @@ public class PermissionInfo extends SharedSubCommand { } private static final Comparator ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> { - int i = CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()); + int i = o1.getPermission().compareTo(o2.getPermission()); if (i != 0) { return i; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java index b7757b0c..90944fc2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java @@ -26,6 +26,7 @@ package me.lucko.luckperms.common.commands.log; import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.command.CommandResult; import me.lucko.luckperms.common.command.abstraction.SubCommand; @@ -54,7 +55,7 @@ public class LogNotify extends SubCommand { return false; } - Optional ret = user.getOwnNodes().stream() + Optional ret = user.enduringData().immutable().get(ContextSet.empty()).stream() .filter(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring")) .findFirst(); @@ -74,7 +75,7 @@ public class LogNotify extends SubCommand { user.setPermission(NodeFactory.make("luckperms.log.notify.ignoring")); } else { // remove the perm - user.removeIf(n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring")); + user.removeIf(ContextSet.empty(), n -> n.getPermission().equalsIgnoreCase("luckperms.log.notify.ignoring")); } plugin.getStorage().saveUser(user).join(); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java index ce61ffa5..83be3bb0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java @@ -85,7 +85,7 @@ public class ExportCommand extends SingleCommand { Exporter exporter = new Exporter(plugin, sender, path, includeUsers); // Run the exporter in its own thread. - plugin.getBootstrap().getScheduler().doAsync(() -> { + plugin.getBootstrap().getScheduler().executeAsync(() -> { try { exporter.run(); } finally { diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java index 03d507c3..daa39c18 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ImportCommand.java @@ -86,7 +86,7 @@ public class ImportCommand extends SingleCommand { Importer importer = new Importer(plugin.getCommandManager(), sender, commands); // Run the importer in its own thread. - plugin.getBootstrap().getScheduler().doAsync(() -> { + plugin.getBootstrap().getScheduler().executeAsync(() -> { try { importer.run(); } finally { diff --git a/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java b/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java index 5a581a9f..fe370fa3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java @@ -25,34 +25,31 @@ package me.lucko.luckperms.common.config; -import com.github.benmanes.caffeine.cache.CacheLoader; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; - import me.lucko.luckperms.common.api.delegates.misc.ApiConfiguration; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; import me.lucko.luckperms.common.config.keys.EnduringKey; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.annotation.Nonnull; +import java.util.Map; /** - * An abstract implementation of {@link LuckPermsConfiguration}, backed by a cache. + * An abstract implementation of {@link LuckPermsConfiguration}. + * + *

Values are loaded into memory on init.

*/ -public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoader, Optional> { +public class AbstractConfiguration implements LuckPermsConfiguration { - // the loading cache for config keys --> their value - // the value is wrapped in an optional as null values don't get cached. - private final LoadingCache, Optional> cache = Caffeine.newBuilder().build(this); + /** + * The configurations loaded values. + * + *

The value corresponding to each key is stored at the index defined + * by {@link ConfigKey#ordinal()}.

+ */ + private Object[] values = null; - // the plugin instance private final LuckPermsPlugin plugin; - // the adapter used to read values private final ConfigurationAdapter adapter; + // the api delegate private final ApiConfiguration delegate = new ApiConfiguration(this); // the contextsfile handler @@ -61,6 +58,52 @@ public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoade public AbstractConfiguration(LuckPermsPlugin plugin, ConfigurationAdapter adapter) { this.plugin = plugin; this.adapter = adapter; + + load(); + } + + @SuppressWarnings("unchecked") + @Override + public T get(ConfigKey key) { + return (T) this.values[key.ordinal()]; + } + + @Override + public synchronized void load() { + // get the map of all keys + Map> keys = ConfigKeys.getAllKeys(); + + // if this is a reload operation + boolean reload = true; + + // if values are null, must be loading for the first time + if (this.values == null) { + this.values = new Object[keys.size()]; + reload = false; + } + + // load a value for each key. + for (ConfigKey key : keys.values()) { + // don't reload enduring keys. + if (reload && key instanceof EnduringKey) { + continue; + } + + // load the value for the key + Object value = key.get(this.adapter); + this.values[key.ordinal()] = value; + } + + // load the contexts file + this.contextsFile.load(); + } + + @Override + public void reload() { + this.adapter.reload(); + load(); + + getPlugin().getEventFactory().handleConfigReload(); } public ConfigurationAdapter getAdapter() { @@ -81,36 +124,4 @@ public class AbstractConfiguration implements LuckPermsConfiguration, CacheLoade public ContextsFile getContextsFile() { return this.contextsFile; } - - @SuppressWarnings("unchecked") - @Override - public T get(ConfigKey key) { - Optional ret = this.cache.get(key); - if (ret == null) { - return null; - } - return (T) ret.orElse(null); - } - - @Override - public void loadAll() { - ConfigKeys.getAllKeys().values().forEach(this.cache::get); - this.contextsFile.load(); - } - - @Override - public void reload() { - this.adapter.reload(); - - Set> toInvalidate = this.cache.asMap().keySet().stream().filter(k -> !(k instanceof EnduringKey)).collect(Collectors.toSet()); - this.cache.invalidateAll(toInvalidate); - - loadAll(); - getPlugin().getEventFactory().handleConfigReload(); - } - - @Override - public Optional load(@Nonnull ConfigKey key) { - return Optional.ofNullable(key.get(this.adapter)); - } } diff --git a/common/src/main/java/me/lucko/luckperms/common/calculators/PlatformCalculatorFactory.java b/common/src/main/java/me/lucko/luckperms/common/config/BaseConfigKey.java similarity index 77% rename from common/src/main/java/me/lucko/luckperms/common/calculators/PlatformCalculatorFactory.java rename to common/src/main/java/me/lucko/luckperms/common/config/BaseConfigKey.java index f6a28624..5c4deeab 100644 --- a/common/src/main/java/me/lucko/luckperms/common/calculators/PlatformCalculatorFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/BaseConfigKey.java @@ -23,17 +23,17 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.calculators; +package me.lucko.luckperms.common.config; -/** - * Extension of {@link CalculatorFactory} which keeps a record of produced - * calculators and provides a means to invalidate them all in bulk. - */ -public interface PlatformCalculatorFactory extends CalculatorFactory { +public abstract class BaseConfigKey implements ConfigKey { + int ordinal = -1; - /** - * Invalidates all calculators build by this factory - */ - void invalidateAll(); + protected BaseConfigKey() { + } + + @Override + public int ordinal() { + return this.ordinal; + } } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKey.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKey.java index d495f0ee..1b5c369c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKey.java @@ -34,6 +34,16 @@ import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; */ public interface ConfigKey { + /** + * Gets the position of this key within the {@link ConfigKeys} enum. + * + *

This is lazily set when the configuration is loaded for the first time, during the + * execution of {@link ConfigKeys#getAllKeys()}.

+ * + * @return the position + */ + int ordinal(); + /** * Resolves and returns the value mapped to this key using the given config instance. * diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java index e0418711..bc03db97 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java @@ -33,8 +33,8 @@ import me.lucko.luckperms.api.LookupSetting; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.common.assignments.AssignmentRule; -import me.lucko.luckperms.common.config.keys.AbstractKey; import me.lucko.luckperms.common.config.keys.BooleanKey; +import me.lucko.luckperms.common.config.keys.CustomKey; import me.lucko.luckperms.common.config.keys.EnduringKey; import me.lucko.luckperms.common.config.keys.LowercaseStringKey; import me.lucko.luckperms.common.config.keys.MapKey; @@ -64,13 +64,16 @@ import java.util.function.Function; /** * All of the {@link ConfigKey}s used by LuckPerms. + * + *

The {@link #getAllKeys()} method and associated behaviour allows this class to behave + * a bit like an enum with generics.

*/ -public class ConfigKeys { +public final class ConfigKeys { /** * The name of the server */ - public static final ConfigKey SERVER = AbstractKey.of(c -> { + public static final ConfigKey SERVER = CustomKey.of(c -> { if (c.getBoolean("use-server-properties-name", false)) { String serverName = c.getPlugin().getBootstrap().getServerName(); if (serverName != null && !serverName.equals("Unknown Server")) { @@ -84,7 +87,7 @@ public class ConfigKeys { /** * How many minutes to wait between syncs. A value <= 0 will disable syncing. */ - public static final ConfigKey SYNC_TIME = EnduringKey.wrap(AbstractKey.of(c -> { + public static final ConfigKey SYNC_TIME = EnduringKey.wrap(CustomKey.of(c -> { int val = c.getInt("sync-minutes", -1); if (val == -1) { val = c.getInt("data.sync-minutes", -1); @@ -95,7 +98,7 @@ public class ConfigKeys { /** * The lookup settings for contexts (care should be taken to not mutate this method) */ - public static final ConfigKey> LOOKUP_SETTINGS = AbstractKey.of(c -> { + public static final ConfigKey> LOOKUP_SETTINGS = CustomKey.of(c -> { return EnumSet.copyOf(Contexts.of( ContextSet.empty(), c.getBoolean("include-global", true), @@ -130,7 +133,7 @@ public class ConfigKeys { /** * Controls how temporary add commands should behave */ - public static final ConfigKey TEMPORARY_ADD_BEHAVIOUR = AbstractKey.of(c -> { + public static final ConfigKey TEMPORARY_ADD_BEHAVIOUR = CustomKey.of(c -> { String option = c.getString("temporary-add-behaviour", "deny").toLowerCase(); if (!option.equals("deny") && !option.equals("replace") && !option.equals("accumulate")) { option = "deny"; @@ -142,7 +145,7 @@ public class ConfigKeys { /** * How primary groups should be calculated. */ - public static final ConfigKey PRIMARY_GROUP_CALCULATION_METHOD = EnduringKey.wrap(AbstractKey.of(c -> { + public static final ConfigKey PRIMARY_GROUP_CALCULATION_METHOD = EnduringKey.wrap(CustomKey.of(c -> { String option = c.getString("primary-group-calculation", "stored").toLowerCase(); if (!option.equals("stored") && !option.equals("parents-by-weight") && !option.equals("all-parents-by-weight")) { option = "stored"; @@ -154,7 +157,7 @@ public class ConfigKeys { /** * A function to create primary group holder instances based upon the {@link #PRIMARY_GROUP_CALCULATION_METHOD} setting. */ - public static final ConfigKey> PRIMARY_GROUP_CALCULATION = EnduringKey.wrap(AbstractKey.of(c -> { + public static final ConfigKey> PRIMARY_GROUP_CALCULATION = EnduringKey.wrap(CustomKey.of(c -> { String option = PRIMARY_GROUP_CALCULATION_METHOD.get(c); switch (option) { case "stored": @@ -245,7 +248,7 @@ public class ConfigKeys { /** * The algorithm LuckPerms should use when traversing the "inheritance tree" */ - public static final ConfigKey INHERITANCE_TRAVERSAL_ALGORITHM = AbstractKey.of(c -> { + public static final ConfigKey INHERITANCE_TRAVERSAL_ALGORITHM = CustomKey.of(c -> { String value = c.getString("inheritance-traversal-algorithm", "depth-first-pre-order"); switch (value.toLowerCase()) { case "breadth-first": @@ -260,7 +263,7 @@ public class ConfigKeys { /** * The configured group weightings */ - public static final ConfigKey> GROUP_WEIGHTS = AbstractKey.of(c -> { + public static final ConfigKey> GROUP_WEIGHTS = CustomKey.of(c -> { return c.getMap("group-weight", ImmutableMap.of()).entrySet().stream().collect(ImmutableCollectors.toMap( e -> e.getKey().toLowerCase(), e -> { @@ -276,7 +279,7 @@ public class ConfigKeys { /** * Creates a new prefix MetaStack element based upon the configured values. */ - public static final ConfigKey PREFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> { + public static final ConfigKey PREFIX_FORMATTING_OPTIONS = CustomKey.of(l -> { List format = l.getList("meta-formatting.prefix.format", new ArrayList<>()); if (format.isEmpty()) { format.add("highest"); @@ -291,7 +294,7 @@ public class ConfigKeys { /** * Creates a new suffix MetaStack element based upon the configured values. */ - public static final ConfigKey SUFFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> { + public static final ConfigKey SUFFIX_FORMATTING_OPTIONS = CustomKey.of(l -> { List format = l.getList("meta-formatting.suffix.format", new ArrayList<>()); if (format.isEmpty()) { format.add("highest"); @@ -316,7 +319,7 @@ public class ConfigKeys { /** * If server operators should be enabled. Only used by the Bukkit platform. */ - public static final ConfigKey OPS_ENABLED = EnduringKey.wrap(AbstractKey.of(c -> !AUTO_OP.get(c) && c.getBoolean("enable-ops", true))); + public static final ConfigKey OPS_ENABLED = EnduringKey.wrap(CustomKey.of(c -> !AUTO_OP.get(c) && c.getBoolean("enable-ops", true))); /** * If server operators should be able to use LuckPerms commands by default. Only used by the Bukkit platform. @@ -331,7 +334,7 @@ public class ConfigKeys { /** * The name of the server to use for Vault. */ - public static final ConfigKey VAULT_SERVER = AbstractKey.of(c -> { + public static final ConfigKey VAULT_SERVER = CustomKey.of(c -> { // default to true for backwards compatibility if (USE_VAULT_SERVER.get(c)) { return c.getString("vault-server", "global").toLowerCase(); @@ -358,7 +361,7 @@ public class ConfigKeys { /** * The world rewrites map */ - public static final ConfigKey> WORLD_REWRITES = AbstractKey.of(c -> { + public static final ConfigKey> WORLD_REWRITES = CustomKey.of(c -> { return c.getMap("world-rewrite", ImmutableMap.of()).entrySet().stream() .collect(ImmutableCollectors.toMap( e -> e.getKey().toLowerCase(), @@ -374,7 +377,7 @@ public class ConfigKeys { /** * The default assignments being applied by the plugin */ - public static final ConfigKey> DEFAULT_ASSIGNMENTS = AbstractKey.of(c -> { + public static final ConfigKey> DEFAULT_ASSIGNMENTS = CustomKey.of(c -> { return c.getObjectList("default-assignments", ImmutableList.of()).stream().map(name -> { String hasTrue = c.getString("default-assignments." + name + ".if.has-true", null); String hasFalse = c.getString("default-assignments." + name + ".if.has-false", null); @@ -389,7 +392,7 @@ public class ConfigKeys { /** * The database settings, username, password, etc for use by any database */ - public static final ConfigKey DATABASE_VALUES = EnduringKey.wrap(AbstractKey.of(c -> { + public static final ConfigKey DATABASE_VALUES = EnduringKey.wrap(CustomKey.of(c -> { int maxPoolSize = c.getInt("data.pool-settings.maximum-pool-size", c.getInt("data.pool-size", 10)); int minIdle = c.getInt("data.pool-settings.minimum-idle", maxPoolSize); int maxLifetime = c.getInt("data.pool-settings.maximum-lifetime", 1800000); @@ -438,7 +441,7 @@ public class ConfigKeys { /** * The options for split storage */ - public static final ConfigKey> SPLIT_STORAGE_OPTIONS = EnduringKey.wrap(AbstractKey.of(c -> { + public static final ConfigKey> SPLIT_STORAGE_OPTIONS = EnduringKey.wrap(CustomKey.of(c -> { EnumMap map = new EnumMap<>(SplitStorageType.class); map.put(SplitStorageType.USER, c.getString("split-storage.methods.user", "h2").toLowerCase()); map.put(SplitStorageType.GROUP, c.getString("split-storage.methods.group", "h2").toLowerCase()); @@ -511,15 +514,25 @@ public class ConfigKeys { try { Field[] values = ConfigKeys.class.getFields(); + int counter = 0; + for (Field f : values) { + // ignore non-static fields if (!Modifier.isStatic(f.getModifiers())) { continue; } - Object val = f.get(null); - if (val instanceof ConfigKey) { - keys.put(f.getName(), (ConfigKey) val); + // ignore fields that aren't configkeys + if (!ConfigKey.class.equals(f.getType())) { + continue; } + + // get the key instance + BaseConfigKey key = (BaseConfigKey) f.get(null); + // set the ordinal value of the key. + key.ordinal = counter++; + // add the key to the return map + keys.put(f.getName(), key); } } catch (Exception e) { e.printStackTrace(); diff --git a/common/src/main/java/me/lucko/luckperms/common/config/LuckPermsConfiguration.java b/common/src/main/java/me/lucko/luckperms/common/config/LuckPermsConfiguration.java index 78223e8e..8c696eae 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/LuckPermsConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/LuckPermsConfiguration.java @@ -60,9 +60,9 @@ public interface LuckPermsConfiguration { void reload(); /** - * Pre-loads all configuration keys into the cache. + * Loads all configuration values. */ - void loadAll(); + void load(); /** * Gets the value of a given context key. diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/BooleanKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/BooleanKey.java index 3b3b258a..6f2b033c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/BooleanKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/BooleanKey.java @@ -25,10 +25,10 @@ package me.lucko.luckperms.common.config.keys; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; -public class BooleanKey implements ConfigKey { +public class BooleanKey extends BaseConfigKey { public static BooleanKey of(String path, boolean def) { return new BooleanKey(path, def); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/AbstractKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/CustomKey.java similarity index 84% rename from common/src/main/java/me/lucko/luckperms/common/config/keys/AbstractKey.java rename to common/src/main/java/me/lucko/luckperms/common/config/keys/CustomKey.java index dc562d52..8f7a349e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/AbstractKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/CustomKey.java @@ -25,19 +25,19 @@ package me.lucko.luckperms.common.config.keys; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; import java.util.function.Function; -public class AbstractKey implements ConfigKey { - public static AbstractKey of(Function function) { - return new AbstractKey<>(function); +public class CustomKey extends BaseConfigKey { + public static CustomKey of(Function function) { + return new CustomKey<>(function); } private final Function function; - private AbstractKey(Function function) { + private CustomKey(Function function) { this.function = function; } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/EnduringKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/EnduringKey.java index 4ab9268c..a97d7d70 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/EnduringKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/EnduringKey.java @@ -25,6 +25,7 @@ package me.lucko.luckperms.common.config.keys; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.ConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; @@ -32,7 +33,7 @@ import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; * Wrapper class to mark a config key as enduring (doesn't change in the event of a reload) * @param */ -public class EnduringKey implements ConfigKey { +public class EnduringKey extends BaseConfigKey { public static EnduringKey wrap(ConfigKey delegate) { return new EnduringKey<>(delegate); diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/IntegerKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/IntegerKey.java index ae42f7c9..9daa5801 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/IntegerKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/IntegerKey.java @@ -25,10 +25,10 @@ package me.lucko.luckperms.common.config.keys; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; -public class IntegerKey implements ConfigKey { +public class IntegerKey extends BaseConfigKey { public static IntegerKey of(String path, int def) { return new IntegerKey(path, def); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/LowercaseStringKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/LowercaseStringKey.java index 0ecf42b8..828514da 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/LowercaseStringKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/LowercaseStringKey.java @@ -25,10 +25,10 @@ package me.lucko.luckperms.common.config.keys; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; -public class LowercaseStringKey implements ConfigKey { +public class LowercaseStringKey extends BaseConfigKey { public static LowercaseStringKey of(String path, String def) { return new LowercaseStringKey(path, def); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/MapKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/MapKey.java index 0443747f..c2829c3c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/MapKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/MapKey.java @@ -27,12 +27,12 @@ package me.lucko.luckperms.common.config.keys; import com.google.common.collect.ImmutableMap; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; import java.util.Map; -public class MapKey implements ConfigKey> { +public class MapKey extends BaseConfigKey> { public static MapKey of(String path) { return new MapKey(path); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/keys/StringKey.java b/common/src/main/java/me/lucko/luckperms/common/config/keys/StringKey.java index ab24fc88..191371a4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/keys/StringKey.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/keys/StringKey.java @@ -25,10 +25,10 @@ package me.lucko.luckperms.common.config.keys; -import me.lucko.luckperms.common.config.ConfigKey; +import me.lucko.luckperms.common.config.BaseConfigKey; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; -public class StringKey implements ConfigKey { +public class StringKey extends BaseConfigKey { public static StringKey of(String path, String def) { return new StringKey(path, def); } diff --git a/common/src/main/java/me/lucko/luckperms/common/event/AbstractEventBus.java b/common/src/main/java/me/lucko/luckperms/common/event/AbstractEventBus.java index 2b67690a..bc0b3387 100644 --- a/common/src/main/java/me/lucko/luckperms/common/event/AbstractEventBus.java +++ b/common/src/main/java/me/lucko/luckperms/common/event/AbstractEventBus.java @@ -221,6 +221,6 @@ public abstract class AbstractEventBus

implements EventBus, AutoCloseable { if (event instanceof Cancellable) { throw new IllegalArgumentException("cannot call Cancellable event async"); } - this.plugin.getBootstrap().getScheduler().doAsync(() -> fireEvent(event)); + this.plugin.getBootstrap().getScheduler().executeAsync(() -> fireEvent(event)); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceHandler.java b/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceHandler.java index 4588c955..46f582e5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceHandler.java +++ b/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceHandler.java @@ -25,9 +25,6 @@ package me.lucko.luckperms.common.inheritance; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; - import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.LookupSetting; import me.lucko.luckperms.api.Node; @@ -38,7 +35,6 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.List; import java.util.Set; import java.util.TreeSet; -import java.util.concurrent.TimeUnit; /** * Provides {@link InheritanceGraph}s. @@ -51,17 +47,15 @@ public class InheritanceHandler { */ private final InheritanceGraph nonContextualGraph; - /** - * Cache of contextual inheritance graph instances - */ - private final LoadingCache contextualGraphs; + // some cached contextual graphs for common Contexts + private final InheritanceGraph allowAllContextualGraph; + private final InheritanceGraph globalContextualGraph; public InheritanceHandler(LuckPermsPlugin plugin) { this.plugin = plugin; this.nonContextualGraph = new NonContextualGraph(plugin); - this.contextualGraphs = Caffeine.newBuilder() - .expireAfterAccess(10, TimeUnit.MINUTES) - .build(key -> new ContextualGraph(this.plugin, key)); + this.allowAllContextualGraph = new ContextualGraph(plugin, Contexts.allowAll()); + this.globalContextualGraph = new ContextualGraph(plugin, Contexts.global()); } public InheritanceGraph getGraph() { @@ -69,7 +63,14 @@ public class InheritanceHandler { } public InheritanceGraph getGraph(Contexts contexts) { - return this.contextualGraphs.get(contexts); + if (contexts == Contexts.allowAll()) { + return this.allowAllContextualGraph; + } + if (contexts == Contexts.global()) { + return this.globalContextualGraph; + } + + return new ContextualGraph(this.plugin, contexts); } private static final class NonContextualGraph implements InheritanceGraph { diff --git a/common/src/main/java/me/lucko/luckperms/common/managers/user/AbstractUserManager.java b/common/src/main/java/me/lucko/luckperms/common/managers/user/AbstractUserManager.java index fe16c3c1..75ef8ff4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/managers/user/AbstractUserManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/managers/user/AbstractUserManager.java @@ -37,6 +37,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; public abstract class AbstractUserManager extends AbstractManager implements UserManager { @@ -46,7 +47,7 @@ public abstract class AbstractUserManager extends AbstractManage public AbstractUserManager(LuckPermsPlugin plugin, UserHousekeeper.TimeoutSettings timeoutSettings) { this.plugin = plugin; this.housekeeper = new UserHousekeeper(plugin, this, timeoutSettings); - this.plugin.getBootstrap().getScheduler().asyncRepeating(this.housekeeper, 200L); // every 10 seconds + this.plugin.getBootstrap().getScheduler().asyncRepeating(this.housekeeper, 10, TimeUnit.SECONDS); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java index 01893b6b..4e6a5142 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java @@ -102,7 +102,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco @Override public void pushUpdate() { - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { UUID requestId = generatePingId(); this.plugin.getLogger().info("[" + getName() + " Messaging] Sending ping with id: " + requestId); this.messenger.sendOutgoingMessage(new UpdateMessageImpl(requestId)); @@ -111,7 +111,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco @Override public void pushUserUpdate(User user) { - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { UUID requestId = generatePingId(); this.plugin.getLogger().info("[" + getName() + " Messaging] Sending user ping for '" + user.getFriendlyName() + "' with id: " + requestId); this.messenger.sendOutgoingMessage(new UserUpdateMessageImpl(requestId, user.getUuid())); @@ -120,7 +120,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco @Override public void pushLog(LogEntry logEntry) { - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { UUID requestId = generatePingId(); if (this.plugin.getEventFactory().handleLogNetworkPublish(!this.plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), requestId, logEntry)) { diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java b/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java index 427d90eb..831398be 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/redis/RedisMessenger.java @@ -65,7 +65,7 @@ public class RedisMessenger implements Messenger { this.jedisPool = new JedisPool(new JedisPoolConfig(), host, port, 0, password); } - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { this.sub = new LPSub(this); try (Jedis jedis = this.jedisPool.getResource()) { jedis.subscribe(this.sub, CHANNEL); diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/sql/SqlMessenger.java b/common/src/main/java/me/lucko/luckperms/common/messaging/sql/SqlMessenger.java index 1327d4e8..c8bea759 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/sql/SqlMessenger.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/sql/SqlMessenger.java @@ -27,12 +27,13 @@ package me.lucko.luckperms.common.messaging.sql; import me.lucko.luckperms.api.messenger.IncomingMessageConsumer; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.plugin.SchedulerTask; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.storage.dao.sql.SqlDao; import java.sql.Connection; import java.sql.SQLException; +import java.util.concurrent.TimeUnit; public class SqlMessenger extends AbstractSqlMessenger { private final LuckPermsPlugin plugin; @@ -57,8 +58,8 @@ public class SqlMessenger extends AbstractSqlMessenger { // schedule poll tasks SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler(); - this.pollTask = scheduler.asyncRepeating(this::pollMessages, 20L); - this.housekeepingTask = scheduler.asyncRepeating(this::runHousekeeping, 20L * 30); + this.pollTask = scheduler.asyncRepeating(this::pollMessages, 1, TimeUnit.SECONDS); + this.housekeepingTask = scheduler.asyncRepeating(this::runHousekeeping, 30, TimeUnit.SECONDS); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeComparator.java b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeComparator.java index 0cc08d0c..7b74c898 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeComparator.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeComparator.java @@ -26,7 +26,6 @@ package me.lucko.luckperms.common.node.comparator; import me.lucko.luckperms.api.Node; -import me.lucko.luckperms.common.utils.CollationKeyCache; import java.util.Comparator; @@ -65,6 +64,6 @@ public class NodeComparator implements Comparator { return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1; } - return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1; + return o1.getPermission().compareTo(o2.getPermission()) > 0 ? -1 : 1; } } diff --git a/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeWithContextComparator.java b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeWithContextComparator.java index f9120cca..42cdf07d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeWithContextComparator.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeWithContextComparator.java @@ -26,7 +26,7 @@ package me.lucko.luckperms.common.node.comparator; import me.lucko.luckperms.api.Node; -import me.lucko.luckperms.common.utils.CollationKeyCache; +import me.lucko.luckperms.common.contexts.ContextSetComparator; import java.util.Comparator; @@ -58,35 +58,16 @@ public class NodeWithContextComparator implements Comparator { return o1.isOverride() ? 1 : -1; } - if (o1.isServerSpecific() != o2.isServerSpecific()) { - return o1.isServerSpecific() ? 1 : -1; + int i = ContextSetComparator.normal().compare( + o1.getFullContexts().makeImmutable(), + o2.getFullContexts().makeImmutable() + ); + + if (i != 0) { + return i; } - if (o1.isWorldSpecific() != o2.isWorldSpecific()) { - return o1.isWorldSpecific() ? 1 : -1; - } - - if (o1.getContexts().size() != o2.getContexts().size()) { - return o1.getContexts().size() > o2.getContexts().size() ? 1 : -1; - } - - if (o1.isTemporary() != o2.isTemporary()) { - return o1.isTemporary() ? 1 : -1; - } - - if (o1.isWildcard() != o2.isWildcard()) { - return o1.isWildcard() ? 1 : -1; - } - - if (o1.isTemporary()) { - return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1; - } - - if (o1.isWildcard()) { - return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1; - } - - return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1; + return NodeComparator.normal().compare(o1, o2); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/ForwardingNode.java b/common/src/main/java/me/lucko/luckperms/common/node/model/ForwardingNode.java index a861dce6..2333c072 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/ForwardingNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/model/ForwardingNode.java @@ -42,7 +42,7 @@ import javax.annotation.Nonnull; public abstract class ForwardingNode implements Node { - protected abstract Node delegate(); + public abstract Node delegate(); @Override public int hashCode() { diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableLocalizedNode.java b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableLocalizedNode.java index 0810dee8..613e8695 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableLocalizedNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableLocalizedNode.java @@ -52,7 +52,7 @@ public final class ImmutableLocalizedNode extends ForwardingNode implements Loca } @Override - protected Node delegate() { + public Node delegate() { return this.node; } diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableNode.java b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableNode.java index e49c2e2f..03b8be79 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableNode.java @@ -85,7 +85,6 @@ public final class ImmutableNode implements Node { // cached state - private final Optional optServer; private final Optional optWorld; diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableTransientNode.java b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableTransientNode.java index fc330cd1..47aca455 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableTransientNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/model/ImmutableTransientNode.java @@ -48,7 +48,7 @@ public final class ImmutableTransientNode extends ForwardingNode implements N } @Override - protected Node delegate() { + public Node delegate() { return this.node; } diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java index 69498f80..abd15855 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java @@ -31,7 +31,7 @@ import me.lucko.luckperms.common.api.ApiRegistrationUtil; import me.lucko.luckperms.common.api.LuckPermsApiProvider; import me.lucko.luckperms.common.buffers.BufferedRequest; import me.lucko.luckperms.common.buffers.UpdateTaskBuffer; -import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.command.utils.MessageUtils; import me.lucko.luckperms.common.config.AbstractConfiguration; import me.lucko.luckperms.common.config.ConfigKeys; @@ -61,6 +61,7 @@ import me.lucko.luckperms.common.verbose.VerboseHandler; import java.io.IOException; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { @@ -79,7 +80,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { private InternalMessagingService messagingService = null; private BufferedRequest updateTaskBuffer; private InheritanceHandler inheritanceHandler; - private PlatformCalculatorFactory calculatorFactory; + private CalculatorFactory calculatorFactory; private LuckPermsApiProvider apiProvider; private EventFactory eventFactory; @@ -101,14 +102,13 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { displayBanner(getConsoleSender()); // load some utilities early - this.verboseHandler = new VerboseHandler(); - this.permissionRegistry = new PermissionRegistry(); + this.verboseHandler = new VerboseHandler(getBootstrap().getScheduler()); + this.permissionRegistry = new PermissionRegistry(getBootstrap().getScheduler()); this.logDispatcher = new LogDispatcher(this); // load configuration getLogger().info("Loading configuration..."); this.configuration = new AbstractConfiguration(this, provideConfigurationAdapter()); - this.configuration.loadAll(); // load locale this.localeManager = new SimpleLocaleManager(); @@ -168,10 +168,9 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { // schedule update tasks int mins = getConfiguration().get(ConfigKeys.SYNC_TIME); if (mins > 0) { - long ticks = mins * 60 * 20; - getBootstrap().getScheduler().asyncRepeating(() -> this.updateTaskBuffer.request(), ticks); + getBootstrap().getScheduler().asyncRepeating(() -> this.updateTaskBuffer.request(), mins, TimeUnit.MINUTES); } - getBootstrap().getScheduler().asyncLater(() -> this.updateTaskBuffer.request(), 40L); + getBootstrap().getScheduler().asyncLater(() -> this.updateTaskBuffer.request(), 2, TimeUnit.SECONDS); // run an update instantly. getLogger().info("Performing initial data load..."); @@ -191,9 +190,6 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { } public final void disable() { - // perform initial disable tasks - performEarlyDisableTasks(); - // shutdown permission vault and verbose handler tasks this.permissionRegistry.stop(); this.verboseHandler.stop(); @@ -233,7 +229,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { protected abstract MessagingFactory provideMessagingFactory(); protected abstract void registerCommands(); protected abstract void setupManagers(); - protected abstract PlatformCalculatorFactory provideCalculatorFactory(); + protected abstract CalculatorFactory provideCalculatorFactory(); protected abstract void setupContextManager(); protected abstract void setupPlatformHooks(); protected abstract AbstractEventBus provideEventBus(LuckPermsApiProvider apiProvider); @@ -241,7 +237,6 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { protected abstract void registerHousekeepingTasks(); protected abstract void performFinalSetup(); - protected void performEarlyDisableTasks() {} protected void removePlatformHooks() {} @Override @@ -312,7 +307,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { } @Override - public PlatformCalculatorFactory getCalculatorFactory() { + public CalculatorFactory getCalculatorFactory() { return this.calculatorFactory; } diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/bootstrap/LuckPermsBootstrap.java b/common/src/main/java/me/lucko/luckperms/common/plugin/bootstrap/LuckPermsBootstrap.java index c354873a..22e370ff 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/bootstrap/LuckPermsBootstrap.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/bootstrap/LuckPermsBootstrap.java @@ -27,7 +27,7 @@ package me.lucko.luckperms.common.plugin.bootstrap; import me.lucko.luckperms.api.platform.PlatformType; import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import java.io.InputStream; import java.nio.file.Path; diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/AbstractJavaScheduler.java b/common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/AbstractJavaScheduler.java new file mode 100644 index 00000000..817ae850 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/AbstractJavaScheduler.java @@ -0,0 +1,98 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.plugin.scheduler; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import me.lucko.luckperms.common.plugin.SchedulerTask; + +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Abstract implementation of {@link SchedulerAdapter} using a {@link ScheduledExecutorService}. + */ +public abstract class AbstractJavaScheduler implements SchedulerAdapter { + private final ScheduledExecutorService asyncExecutor = new AsyncExecutor(); + + @Override + public Executor async() { + return this.asyncExecutor; + } + + @Override + public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) { + ScheduledFuture future = this.asyncExecutor.schedule(new WrappedRunnable(task), delay, unit); + return () -> future.cancel(false); + } + + @Override + public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) { + ScheduledFuture future = this.asyncExecutor.scheduleAtFixedRate(new WrappedRunnable(task), interval, interval, unit); + return () -> future.cancel(false); + } + + @Override + public void shutdown() { + this.asyncExecutor.shutdown(); + try { + this.asyncExecutor.awaitTermination(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static final class WrappedRunnable implements Runnable { + private final Runnable delegate; + + WrappedRunnable(Runnable delegate) { + this.delegate = delegate; + } + + @Override + public void run() { + try { + this.delegate.run(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private static final class AsyncExecutor extends ScheduledThreadPoolExecutor { + AsyncExecutor() { + super(4, new ThreadFactoryBuilder().setNameFormat("luckperms-%d").build()); + } + + @Override + public void execute(Runnable command) { + super.execute(new WrappedRunnable(command)); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/SchedulerAdapter.java b/common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/SchedulerAdapter.java similarity index 58% rename from common/src/main/java/me/lucko/luckperms/common/plugin/SchedulerAdapter.java rename to common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/SchedulerAdapter.java index 9f05f78f..be47bea9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/SchedulerAdapter.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/scheduler/SchedulerAdapter.java @@ -23,9 +23,12 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.plugin; +package me.lucko.luckperms.common.plugin.scheduler; + +import me.lucko.luckperms.common.plugin.SchedulerTask; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; /** * A scheduler for running tasks using the systems provided by the platform @@ -39,10 +42,6 @@ public interface SchedulerAdapter { */ Executor async(); - default Executor platformAsync() { - return async(); - } - /** * Gets a sync executor instance * @@ -51,46 +50,42 @@ public interface SchedulerAdapter { Executor sync(); /** - * Executes a runnable async + * Executes a task async * - * @param runnable the runnable + * @param task the task */ - void doAsync(Runnable runnable); + default void executeAsync(Runnable task) { + async().execute(task); + } /** - * Executes a runnable sync + * Executes a task sync * - * @param runnable the runnable + * @param task the task */ - void doSync(Runnable runnable); + default void executeSync(Runnable task) { + sync().execute(task); + } /** - * Runs a runnable repeatedly until the plugin disables. Will wait for the interval before the first iteration of the task is ran. - * @param runnable the runnable - * @param intervalTicks the interval in ticks. + * Executes the given task with a delay. + * + * @param task the task + * @param delay the delay + * @param unit the unit of delay + * @return the resultant task instance */ - SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks); + SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit); /** - * Runs a runnable repeatedly until the plugin disables. Will wait for the interval before the first iteration of the task is ran. - * @param runnable the runnable - * @param intervalTicks the interval in ticks. + * Executes the given task repeatedly at a given interval. + * + * @param task the task + * @param interval the interval + * @param unit the unit of interval + * @return the resultant task instance */ - SchedulerTask syncRepeating(Runnable runnable, long intervalTicks); - - /** - * Runs a runnable with a delay - * @param runnable the runnable - * @param delayTicks the delay in ticks - */ - SchedulerTask asyncLater(Runnable runnable, long delayTicks); - - /** - * Runs a runnable with a delay - * @param runnable the runnable - * @param delayTicks the delay in ticks - */ - SchedulerTask syncLater(Runnable runnable, long delayTicks); + SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit); /** * Shuts down this executor instance diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/FileWatcher.java b/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/FileWatcher.java index 365f7ae6..9f37ffb9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/FileWatcher.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/dao/file/FileWatcher.java @@ -61,8 +61,8 @@ public class FileWatcher { this.basePath = basePath; this.watchService = basePath.getFileSystem().newWatchService(); - plugin.getBootstrap().getScheduler().asyncLater(this::initLocations, 25L); - plugin.getBootstrap().getScheduler().asyncRepeating(this::tick, 10L); + plugin.getBootstrap().getScheduler().asyncLater(this::initLocations, 5, TimeUnit.SECONDS); + plugin.getBootstrap().getScheduler().asyncRepeating(this::tick, 1, TimeUnit.SECONDS); } public WatchedLocation getWatcher(Path path) { diff --git a/common/src/main/java/me/lucko/luckperms/common/treeview/PermissionRegistry.java b/common/src/main/java/me/lucko/luckperms/common/treeview/PermissionRegistry.java index b58b843a..7d2e9925 100644 --- a/common/src/main/java/me/lucko/luckperms/common/treeview/PermissionRegistry.java +++ b/common/src/main/java/me/lucko/luckperms/common/treeview/PermissionRegistry.java @@ -28,6 +28,7 @@ package me.lucko.luckperms.common.treeview; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.utils.RepeatingTask; import java.util.Collection; @@ -55,8 +56,8 @@ public class PermissionRegistry extends RepeatingTask { // a queue of permission strings to be processed by the tree private final Queue queue; - public PermissionRegistry() { - super(1000, TimeUnit.MILLISECONDS, "luckperms-permission-vault"); + public PermissionRegistry(SchedulerAdapter scheduler) { + super(scheduler, 1, TimeUnit.SECONDS); this.rootNode = new TreeNode(); this.knownPermissions = ConcurrentHashMap.newKeySet(3000); this.queue = new ConcurrentLinkedQueue<>(); diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/CollationKeyCache.java b/common/src/main/java/me/lucko/luckperms/common/utils/CollationKeyCache.java deleted file mode 100644 index b3df1ae9..00000000 --- a/common/src/main/java/me/lucko/luckperms/common/utils/CollationKeyCache.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.utils; - -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; - -import java.text.CollationKey; -import java.text.Collator; -import java.util.Comparator; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -public final class CollationKeyCache implements Comparator { - private static final CollationKeyCache INSTANCE = new CollationKeyCache(); - - private static final Collator COLLATOR; - static { - COLLATOR = Collator.getInstance(Locale.ENGLISH); - COLLATOR.setStrength(Collator.IDENTICAL); - COLLATOR.setDecomposition(Collator.FULL_DECOMPOSITION); - } - - private static final LoadingCache CACHE = Caffeine.newBuilder() - .maximumSize(5000) - .expireAfterAccess(5, TimeUnit.MINUTES) - .build(COLLATOR::getCollationKey); - - public static Comparator comparator() { - return INSTANCE; - } - - private CollationKeyCache() { - - } - - @Override - public int compare(String o1, String o2) { - return compareStrings(o1, o2); - } - - public static int compareStrings(String o1, String o2) { - //noinspection StringEquality - if (o1 == o2) { - return 0; - } - - try { - CollationKey o1c = CACHE.get(o1); - CollationKey o2c = CACHE.get(o2); - - if (o1c != null && o2c != null) { - int i = o1c.compareTo(o2c); - if (i != 0) { - return i; - } - } - } catch (Exception e) { - // ignored - } - - // fallback to standard string comparison - return o1.compareTo(o2); - } -} diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/ExpiringSet.java b/common/src/main/java/me/lucko/luckperms/common/utils/ExpiringSet.java index 28144a67..780ba756 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/ExpiringSet.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/ExpiringSet.java @@ -25,8 +25,8 @@ package me.lucko.luckperms.common.utils; +import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ForwardingSet; import java.util.Collection; @@ -36,22 +36,22 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; /** - * A bad expiring set implementation using Caffeine caches + * A simple expiring set implementation using Caffeine caches * * @param element type */ public class ExpiringSet extends ForwardingSet { - private final LoadingCache cache; + private final Cache cache; private final Set setView; public ExpiringSet(long duration, TimeUnit unit) { - this.cache = Caffeine.newBuilder().expireAfterAccess(duration, unit).build(key -> Boolean.TRUE); + this.cache = Caffeine.newBuilder().expireAfterAccess(duration, unit).build(); this.setView = this.cache.asMap().keySet(); } @Override public boolean add(E element) { - this.cache.get(element); // simply requesting the element from the cache is sufficient. + this.cache.put(element, Boolean.TRUE); // we don't care about the return value return true; diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/PatternCache.java b/common/src/main/java/me/lucko/luckperms/common/utils/PatternCache.java index 436d5939..7c223b82 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/PatternCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/PatternCache.java @@ -69,12 +69,12 @@ public final class PatternCache { private final Pattern instance; private final PatternSyntaxException ex; - public CachedPattern(Pattern instance) { + CachedPattern(Pattern instance) { this.instance = instance; this.ex = null; } - public CachedPattern(PatternSyntaxException ex) { + CachedPattern(PatternSyntaxException ex) { this.instance = null; this.ex = ex; } diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/RepeatingTask.java b/common/src/main/java/me/lucko/luckperms/common/utils/RepeatingTask.java index 6f79870f..a77ed3f6 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/RepeatingTask.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/RepeatingTask.java @@ -25,20 +25,16 @@ package me.lucko.luckperms.common.utils; -import com.google.common.util.concurrent.ThreadFactoryBuilder; +import me.lucko.luckperms.common.plugin.SchedulerTask; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public abstract class RepeatingTask { + private final SchedulerTask task; - // the executor thread - private final ScheduledExecutorService executor; - - protected RepeatingTask(long time, TimeUnit unit, String nameFormat) { - this.executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat(nameFormat).build()); - this.executor.scheduleAtFixedRate(this::run, time, time, unit); + protected RepeatingTask(SchedulerAdapter scheduler, long time, TimeUnit unit) { + this.task = scheduler.asyncRepeating(this::run, time, unit); } private void run() { @@ -52,11 +48,6 @@ public abstract class RepeatingTask { protected abstract void tick(); public void stop() { - this.executor.shutdown(); - try { - this.executor.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + this.task.cancel(); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java index 35ab0cb7..9f3d2b1f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java +++ b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java @@ -27,6 +27,7 @@ package me.lucko.luckperms.common.verbose; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.api.context.ContextSet; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.utils.RepeatingTask; @@ -51,8 +52,8 @@ public class VerboseHandler extends RepeatingTask { // if there are any listeners currently registered private boolean listening = false; - public VerboseHandler() { - super(100, TimeUnit.MILLISECONDS, "luckperms-verbose"); + public VerboseHandler(SchedulerAdapter scheduler) { + super(scheduler, 100, TimeUnit.MILLISECONDS); this.listeners = new ConcurrentHashMap<>(); this.queue = new ConcurrentLinkedQueue<>(); } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java index 3519b5c3..32053e51 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java @@ -30,7 +30,7 @@ import me.lucko.luckperms.api.LuckPermsApi; import me.lucko.luckperms.api.event.user.UserDataRecalculateEvent; import me.lucko.luckperms.common.api.LuckPermsApiProvider; import me.lucko.luckperms.common.api.delegates.model.ApiUser; -import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.command.access.CommandPermission; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter; @@ -75,6 +75,7 @@ import java.util.EnumSet; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -145,7 +146,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { } @Override - protected PlatformCalculatorFactory provideCalculatorFactory() { + protected CalculatorFactory provideCalculatorFactory() { return new NukkitCalculatorFactory(this); } @@ -170,7 +171,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { // schedule another injection after all plugins have loaded // the entire pluginmanager instance is replaced by some plugins :( - this.bootstrap.getScheduler().asyncLater(injector, 1L); + this.bootstrap.getServer().getScheduler().scheduleDelayedTask(this.bootstrap, injector, 1, true); } } @@ -186,8 +187,8 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { @Override protected void registerHousekeepingTasks() { - this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L); - this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L); + this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS); + this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES); } @Override @@ -219,16 +220,13 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { }); } - // replace the temporary executor when the Nukkit one starts - this.bootstrap.getServer().getScheduler().scheduleTask(this.bootstrap, () -> this.bootstrap.getScheduler().setUseFallback(false), true); - // Load any online users (in the case of a reload) for (Player player : this.bootstrap.getServer().getOnlinePlayers().values()) { - this.bootstrap.getScheduler().doAsync(() -> { + this.bootstrap.getScheduler().executeAsync(() -> { try { User user = this.connectionListener.loadUser(player.getUniqueId(), player.getName()); if (user != null) { - this.bootstrap.getScheduler().doSync(() -> { + this.bootstrap.getScheduler().executeSync(() -> { try { LPPermissible lpPermissible = new LPPermissible(player, user, this); PermissibleInjector.inject(player, lpPermissible); @@ -244,12 +242,6 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { } } - @Override - protected void performEarlyDisableTasks() { - // Switch back to the fallback executor, the nukkit one won't allow new tasks - this.bootstrap.getScheduler().setUseFallback(true); - } - @Override protected void removePlatformHooks() { // uninject from players diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSchedulerAdapter.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSchedulerAdapter.java index 7b9aac3f..0b29bf3d 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSchedulerAdapter.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSchedulerAdapter.java @@ -25,95 +25,16 @@ package me.lucko.luckperms.nukkit; -import com.google.common.util.concurrent.ThreadFactoryBuilder; +import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; -import me.lucko.luckperms.common.plugin.SchedulerTask; -import me.lucko.luckperms.common.utils.Iterators; - -import cn.nukkit.scheduler.ServerScheduler; -import cn.nukkit.scheduler.TaskHandler; - -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; - -public class NukkitSchedulerAdapter implements SchedulerAdapter { - private final LPNukkitBootstrap bootstrap; - - private final ExecutorService asyncFallback; - private final Executor asyncNukkit; +public class NukkitSchedulerAdapter extends AbstractJavaScheduler implements SchedulerAdapter { private final Executor sync; - private final Executor async; - - private boolean useFallback = true; - - private final Set tasks = ConcurrentHashMap.newKeySet(); public NukkitSchedulerAdapter(LPNukkitBootstrap bootstrap) { - this.bootstrap = bootstrap; - - this.sync = new SyncExecutor(); - this.asyncFallback = new FallbackAsyncExecutor(); - this.asyncNukkit = new NukkitAsyncExecutor(); - this.async = new AsyncExecutor(); - } - - private ServerScheduler scheduler() { - return this.bootstrap.getServer().getScheduler(); - } - - @Override - public void doAsync(Runnable runnable) { - async().execute(runnable); - } - - @Override - public void doSync(Runnable runnable) { - sync().execute(runnable); - } - - @Override - public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) { - SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.bootstrap, runnable, (int) intervalTicks, (int) intervalTicks, true)); - this.tasks.add(task); - return task; - } - - @Override - public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) { - SchedulerTask task = new NukkitSchedulerTask(scheduler().scheduleDelayedRepeatingTask(this.bootstrap, runnable, (int) intervalTicks, (int) intervalTicks, false)); - this.tasks.add(task); - return task; - } - - @Override - public SchedulerTask asyncLater(Runnable runnable, long delayTicks) { - return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.bootstrap, runnable, (int) delayTicks, true)); - } - - @Override - public SchedulerTask syncLater(Runnable runnable, long delayTicks) { - return new NukkitSchedulerTask(scheduler().scheduleDelayedTask(this.bootstrap, runnable, (int) delayTicks, false)); - } - - @Override - public void shutdown() { - Iterators.iterate(this.tasks, SchedulerTask::cancel); - - // wait for executor - this.asyncFallback.shutdown(); - try { - this.asyncFallback.awaitTermination(30, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + this.sync = r -> bootstrap.getServer().getScheduler().scheduleTask(bootstrap, r, false); } @Override @@ -121,62 +42,4 @@ public class NukkitSchedulerAdapter implements SchedulerAdapter { return this.sync; } - @Override - public Executor async() { - return this.async; - } - - @Override - public Executor platformAsync() { - return this.asyncNukkit; - } - - public void setUseFallback(boolean useFallback) { - this.useFallback = useFallback; - } - - private final class SyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - NukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.bootstrap, runnable, false); - } - } - - private final class AsyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - if (NukkitSchedulerAdapter.this.useFallback || !NukkitSchedulerAdapter.this.bootstrap.isEnabled()) { - NukkitSchedulerAdapter.this.asyncFallback.execute(runnable); - } else { - NukkitSchedulerAdapter.this.asyncNukkit.execute(runnable); - } - } - } - - private final class NukkitAsyncExecutor implements Executor { - @Override - public void execute(@Nonnull Runnable runnable) { - NukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleTask(NukkitSchedulerAdapter.this.bootstrap, runnable, true); - } - } - - 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()); - } - } - - private static final class NukkitSchedulerTask implements SchedulerTask { - private final TaskHandler task; - - private NukkitSchedulerTask(TaskHandler task) { - this.task = task; - } - - @Override - public void cancel() { - this.task.cancel(); - } - } - } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java index 9fc06c17..065fe487 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/NukkitSenderFactory.java @@ -69,7 +69,7 @@ public class NukkitSenderFactory extends SenderFactory { } // otherwise, send the message sync - getPlugin().getBootstrap().getScheduler().doSync(new SyncMessengerAgent(sender, s)); + getPlugin().getBootstrap().getScheduler().executeSync(new SyncMessengerAgent(sender, s)); } @Override diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/calculators/NukkitCalculatorFactory.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/calculators/NukkitCalculatorFactory.java index d78933ae..75742462 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/calculators/NukkitCalculatorFactory.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/calculators/NukkitCalculatorFactory.java @@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.LookupSetting; -import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.calculators.PermissionCalculator; import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata; import me.lucko.luckperms.common.config.ConfigKeys; @@ -42,7 +42,7 @@ import me.lucko.luckperms.nukkit.LPNukkitPlugin; import me.lucko.luckperms.nukkit.processors.ChildProcessor; import me.lucko.luckperms.nukkit.processors.DefaultsProcessor; -public class NukkitCalculatorFactory extends AbstractCalculatorFactory { +public class NukkitCalculatorFactory implements CalculatorFactory { private final LPNukkitPlugin plugin; public NukkitCalculatorFactory(LPNukkitPlugin plugin) { @@ -71,6 +71,6 @@ public class NukkitCalculatorFactory extends AbstractCalculatorFactory { processors.add(new DefaultsProcessor(this.plugin, contexts.hasSetting(LookupSetting.IS_OP))); } - return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); + return new PermissionCalculator(this.plugin, metadata, processors.build()); } } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/listeners/NukkitConnectionListener.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/listeners/NukkitConnectionListener.java index 64fe1eaf..235d09a1 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/listeners/NukkitConnectionListener.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/listeners/NukkitConnectionListener.java @@ -183,7 +183,7 @@ public class NukkitConnectionListener extends AbstractConnectionListener impleme this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId()); // force a clear of transient nodes - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId()); if (user != null) { user.clearTransientNodes(); diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/server/LPDefaultsMap.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/server/LPDefaultsMap.java index 218cc887..7f419bc6 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/server/LPDefaultsMap.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/server/LPDefaultsMap.java @@ -29,6 +29,7 @@ import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableMap; import me.lucko.luckperms.api.Tristate; +import me.lucko.luckperms.common.buffers.Cache; import me.lucko.luckperms.nukkit.LPNukkitPlugin; import cn.nukkit.permission.Permission; @@ -39,6 +40,8 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.Nonnull; + /** * A replacement map for the 'defaultPerms' instance in Nukkit's SimplePluginManager. * @@ -58,15 +61,13 @@ public final class LPDefaultsMap { private final Map nonOpSet = new DefaultPermissionSet(false); // fully resolved defaults (accounts for child permissions too) - private Map resolvedOpDefaults = ImmutableMap.of(); - private Map resolvedNonOpDefaults = ImmutableMap.of(); + private DefaultsCache opCache = new DefaultsCache(true); + private DefaultsCache nonOpCache = new DefaultsCache(false); public LPDefaultsMap(LPNukkitPlugin plugin, Map> existingData) { this.plugin = plugin; this.opSet.putAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptyMap())); this.nonOpSet.putAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptyMap())); - refreshOp(); - refreshNonOp(); } public Map getOpPermissions() { @@ -77,6 +78,18 @@ public final class LPDefaultsMap { return this.nonOpSet; } + public Map get(boolean op) { + return op ? this.opSet : this.nonOpSet; + } + + private DefaultsCache getCache(boolean op) { + return op ? this.opCache : this.nonOpCache; + } + + private void invalidate(boolean op) { + getCache(op).invalidate(); + } + /** * Queries whether a given permission should be granted by default. * @@ -85,55 +98,17 @@ public final class LPDefaultsMap { * @return a tristate result */ public Tristate lookupDefaultPermission(String permission, boolean isOp) { - Map map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults; + Map map = getCache(isOp).get(); return Tristate.fromNullableBoolean(map.get(permission)); } - private void refresh(boolean op) { - if (op) { - refreshOp(); - } else { - refreshNonOp(); - } - } - - /** - * Refreshes the op data in this provider. - */ - private void refreshOp() { - Map builder = new HashMap<>(); - for (Permission perm : getOpPermissions().values()) { - String name = perm.getName().toLowerCase(); - builder.put(name, true); - for (Map.Entry child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { - builder.putIfAbsent(child.getKey(), child.getValue()); - } - } - this.resolvedOpDefaults = ImmutableMap.copyOf(builder); - } - - /** - * Refreshes the non op data in this provider. - */ - private void refreshNonOp() { - Map builder = new HashMap<>(); - for (Permission perm : getNonOpPermissions().values()) { - String name = perm.getName().toLowerCase(); - builder.put(name, true); - for (Map.Entry child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { - builder.putIfAbsent(child.getKey(), child.getValue()); - } - } - this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder); - } - final class DefaultPermissionSet extends ForwardingMap { final LPDefaultsMap parent = LPDefaultsMap.this; private final Map delegate = new ConcurrentHashMap<>(); private final boolean op; - private DefaultPermissionSet(boolean op) { + DefaultPermissionSet(boolean op) { this.op = op; } @@ -145,21 +120,43 @@ public final class LPDefaultsMap { @Override public Permission put(String key, Permission value) { Permission ret = super.put(key, value); - refresh(this.op); + invalidate(this.op); return ret; } @Override public Permission putIfAbsent(String key, Permission value) { Permission ret = super.putIfAbsent(key, value); - refresh(this.op); + invalidate(this.op); return ret; } @Override public void putAll(Map map) { super.putAll(map); - refresh(this.op); + invalidate(this.op); + } + } + + private final class DefaultsCache extends Cache> { + private final boolean op; + + DefaultsCache(boolean op) { + this.op = op; + } + + @Nonnull + @Override + protected Map supply() { + Map builder = new HashMap<>(); + for (Permission perm : LPDefaultsMap.this.get(this.op).values()) { + String name = perm.getName().toLowerCase(); + builder.put(name, true); + for (Map.Entry child : LPDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { + builder.putIfAbsent(child.getKey(), child.getValue()); + } + } + return ImmutableMap.copyOf(builder); } } diff --git a/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/CompatibilityUtil.java b/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/CompatibilityUtil.java index 0fd192b5..1a272a9b 100644 --- a/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/CompatibilityUtil.java +++ b/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/CompatibilityUtil.java @@ -25,8 +25,6 @@ package me.lucko.luckperms.sponge.service; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import me.lucko.luckperms.api.Tristate; @@ -39,19 +37,12 @@ import org.spongepowered.api.service.context.Context; import java.util.Objects; import java.util.Set; -import java.util.concurrent.TimeUnit; /** * Utility class for converting between Sponge and LuckPerms context and tristate classes */ public final class CompatibilityUtil { - private static final LoadingCache, ImmutableContextSet> SPONGE_TO_LP_CACHE = Caffeine.newBuilder() - .expireAfterAccess(10, TimeUnit.MINUTES) - .build(ImmutableContextSet::fromEntries); - - private static final LoadingCache> LP_TO_SPONGE_CACHE = Caffeine.newBuilder() - .expireAfterAccess(10, TimeUnit.MINUTES) - .build(DelegatingImmutableContextSet::new); + private static final Set EMPTY = ImmutableSet.of(); public static ImmutableContextSet convertContexts(Set contexts) { Objects.requireNonNull(contexts, "contexts"); @@ -60,12 +51,21 @@ public final class CompatibilityUtil { return ((DelegatingContextSet) contexts).getDelegate().makeImmutable(); } - return SPONGE_TO_LP_CACHE.get(ImmutableSet.copyOf(contexts)); + if (contexts.isEmpty()) { + return ImmutableContextSet.empty(); + } + + return ImmutableContextSet.fromEntries(contexts); } public static Set convertContexts(ContextSet contexts) { Objects.requireNonNull(contexts, "contexts"); - return LP_TO_SPONGE_CACHE.get(contexts.makeImmutable()); + + if (contexts.isEmpty()) { + return EMPTY; + } + + return new DelegatingImmutableContextSet(contexts.makeImmutable()); } public static org.spongepowered.api.util.Tristate convertTristate(Tristate tristate) { diff --git a/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/reference/SubjectReferenceFactory.java b/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/reference/SubjectReferenceFactory.java index 372bffdf..1f9cb58d 100644 --- a/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/reference/SubjectReferenceFactory.java +++ b/sponge/sponge-service/src/main/java/me/lucko/luckperms/sponge/service/reference/SubjectReferenceFactory.java @@ -60,12 +60,13 @@ public final class SubjectReferenceFactory { * * It's perfectly ok if two instances of the same SubjectReference exist. (hence the 1 hour expiry) */ - private final LoadingCache referenceCache = Caffeine.newBuilder() - .expireAfterAccess(1, TimeUnit.HOURS) - .build(a -> new CachedSubjectReference(SubjectReferenceFactory.this.service, a.collectionId, a.id)); + private final LoadingCache referenceCache; public SubjectReferenceFactory(LPPermissionService service) { this.service = service; + this.referenceCache = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .build(a -> new CachedSubjectReference(this.service, a.collectionId, a.id)); } @Deprecated diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongeBootstrap.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongeBootstrap.java index 3f4b1ea0..ed51e24b 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongeBootstrap.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongeBootstrap.java @@ -30,8 +30,8 @@ import com.google.inject.Inject; import me.lucko.luckperms.api.platform.PlatformType; import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader; import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.utils.MoreFiles; import me.lucko.luckperms.sponge.utils.VersionData; diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java index 3f2c8cac..d42805c0 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -28,7 +28,7 @@ package me.lucko.luckperms.sponge; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.LuckPermsApi; import me.lucko.luckperms.common.api.LuckPermsApiProvider; -import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.command.CommandManager; import me.lucko.luckperms.common.command.abstraction.Command; import me.lucko.luckperms.common.command.access.CommandPermission; @@ -75,6 +75,7 @@ import java.util.EnumSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -146,7 +147,7 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin { } @Override - protected PlatformCalculatorFactory provideCalculatorFactory() { + protected CalculatorFactory provideCalculatorFactory() { return new SpongeCalculatorFactory(this); } @@ -189,9 +190,9 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin { @Override protected void registerHousekeepingTasks() { - this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L); - this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L); - this.bootstrap.getScheduler().asyncRepeating(new ServiceCacheHousekeepingTask(this.service), 2400L); + this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS); + this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES); + this.bootstrap.getScheduler().asyncRepeating(new ServiceCacheHousekeepingTask(this.service), 2, TimeUnit.MINUTES); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSchedulerAdapter.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSchedulerAdapter.java index 219c7a1b..4d608f50 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSchedulerAdapter.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSchedulerAdapter.java @@ -25,17 +25,19 @@ package me.lucko.luckperms.sponge; -import me.lucko.luckperms.common.plugin.SchedulerAdapter; import me.lucko.luckperms.common.plugin.SchedulerTask; +import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.utils.Iterators; import org.spongepowered.api.scheduler.Scheduler; import org.spongepowered.api.scheduler.SpongeExecutorService; import org.spongepowered.api.scheduler.Task; +import java.util.Collections; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.WeakHashMap; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; public class SpongeSchedulerAdapter implements SchedulerAdapter { private final LPSpongeBootstrap bootstrap; @@ -44,7 +46,7 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter { private final SpongeExecutorService sync; private final SpongeExecutorService async; - private final Set tasks = ConcurrentHashMap.newKeySet(); + private final Set tasks = Collections.newSetFromMap(new WeakHashMap<>()); public SpongeSchedulerAdapter(LPSpongeBootstrap bootstrap, Scheduler scheduler, SpongeExecutorService sync, SpongeExecutorService async) { this.bootstrap = bootstrap; @@ -64,82 +66,43 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter { } @Override - public void doAsync(Runnable runnable) { + public void executeAsync(Runnable runnable) { this.scheduler.createTaskBuilder().async().execute(runnable).submit(this.bootstrap); } @Override - public void doSync(Runnable runnable) { + public void executeSync(Runnable runnable) { this.scheduler.createTaskBuilder().execute(runnable).submit(this.bootstrap); } @Override - public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) { - Task task = this.scheduler.createTaskBuilder() + public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) { + Task t = this.scheduler.createTaskBuilder() .async() - .intervalTicks(intervalTicks) - .delayTicks(intervalTicks) - .execute(runnable) + .delay(delay, unit) + .execute(task) .submit(this.bootstrap); - SchedulerTask wrapped = new SpongeSchedulerTask(task); - this.tasks.add(wrapped); - return wrapped; + this.tasks.add(t); + return t::cancel; } @Override - public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) { - Task task = this.scheduler.createTaskBuilder() - .intervalTicks(intervalTicks) - .delayTicks(intervalTicks) - .execute(runnable) - .submit(this.bootstrap); - - SchedulerTask wrapped = new SpongeSchedulerTask(task); - this.tasks.add(wrapped); - return wrapped; - } - - @Override - public SchedulerTask asyncLater(Runnable runnable, long delayTicks) { - Task task = this.scheduler.createTaskBuilder() + public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) { + Task t = this.scheduler.createTaskBuilder() .async() - .delayTicks(delayTicks) - .execute(runnable) + .interval(interval, unit) + .delay(interval, unit) + .execute(task) .submit(this.bootstrap); - SchedulerTask wrapped = new SpongeSchedulerTask(task); - this.tasks.add(wrapped); - return wrapped; - } - - @Override - public SchedulerTask syncLater(Runnable runnable, long delayTicks) { - Task task = this.scheduler.createTaskBuilder() - .delayTicks(delayTicks) - .execute(runnable) - .submit(this.bootstrap); - - SchedulerTask wrapped = new SpongeSchedulerTask(task); - this.tasks.add(wrapped); - return wrapped; + this.tasks.add(t); + return t::cancel; } @Override public void shutdown() { - Iterators.iterate(this.tasks, SchedulerTask::cancel); + Iterators.iterate(this.tasks, Task::cancel); } - private static final class SpongeSchedulerTask implements SchedulerTask { - private final Task task; - - private SpongeSchedulerTask(Task task) { - this.task = task; - } - - @Override - public void cancel() { - this.task.cancel(); - } - } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java b/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java index c5136941..b1e74683 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java @@ -28,7 +28,7 @@ package me.lucko.luckperms.sponge.calculators; import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Contexts; -import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory; +import me.lucko.luckperms.common.calculators.CalculatorFactory; import me.lucko.luckperms.common.calculators.PermissionCalculator; import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata; import me.lucko.luckperms.common.config.ConfigKeys; @@ -41,7 +41,7 @@ import me.lucko.luckperms.sponge.processors.GroupDefaultsProcessor; import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor; import me.lucko.luckperms.sponge.processors.UserDefaultsProcessor; -public class SpongeCalculatorFactory extends AbstractCalculatorFactory { +public class SpongeCalculatorFactory implements CalculatorFactory { private final LPSpongePlugin plugin; public SpongeCalculatorFactory(LPSpongePlugin plugin) { @@ -74,6 +74,6 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory { } } - return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); + return new PermissionCalculator(this.plugin, metadata, processors.build()); } } 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 4589f91b..5d4d7684 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 @@ -165,7 +165,7 @@ public class SpongeConnectionListener extends AbstractConnectionListener { this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId()); // force a clear of transient nodes - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId()); if (user != null) { user.clearTransientNodes(); diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsService.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsService.java index 41b202dd..6d1a6b4e 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsService.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsService.java @@ -237,8 +237,6 @@ public class LuckPermsService implements LPPermissionService { subject.invalidateCaches(); } } - - this.plugin.getCalculatorFactory().invalidateAll(); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/event/UpdateEventHandlerImpl.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/event/UpdateEventHandlerImpl.java index 58578f4e..bae7aa20 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/event/UpdateEventHandlerImpl.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/event/UpdateEventHandlerImpl.java @@ -39,7 +39,7 @@ public class UpdateEventHandlerImpl implements UpdateEventHandler { @Override public void fireUpdateEvent(LPSubjectData subjectData) { - this.plugin.getBootstrap().getScheduler().doAsync(() -> { + this.plugin.getBootstrap().getScheduler().executeAsync(() -> { SubjectDataUpdateEvent event = new LPSubjectDataUpdateEvent(this.plugin, subjectData); this.plugin.getBootstrap().getGame().getEventManager().post(event); }); diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/internal/HolderSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/internal/HolderSubject.java index 0c6d72d2..58f24c0f 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/internal/HolderSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/internal/HolderSubject.java @@ -161,7 +161,7 @@ public abstract class HolderSubject implements LPSub @Override public void invalidateCaches() { // invalidate for all changes - this.parent.getCachedData().invalidate(); + this.parent.invalidateCachedData(); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/SubjectDataContainer.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/SubjectDataContainer.java index e8310969..339d770a 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/SubjectDataContainer.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/SubjectDataContainer.java @@ -35,7 +35,6 @@ import com.google.gson.JsonObject; import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.common.contexts.ContextSetComparator; import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer; -import me.lucko.luckperms.common.utils.CollationKeyCache; import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData; import me.lucko.luckperms.sponge.service.model.LPPermissionService; import me.lucko.luckperms.sponge.service.model.LPSubjectData; @@ -204,7 +203,7 @@ public class SubjectDataContainer { // sort alphabetically. List> perms = new ArrayList<>(e.getValue().entrySet()); - perms.sort(Map.Entry.comparingByKey(CollationKeyCache.comparator())); + perms.sort(Map.Entry.comparingByKey()); for (Map.Entry ent : perms) { data.addProperty(ent.getKey(), ent.getValue()); @@ -228,7 +227,7 @@ public class SubjectDataContainer { // sort alphabetically. List> opts = new ArrayList<>(e.getValue().entrySet()); - opts.sort(Map.Entry.comparingByKey(CollationKeyCache.comparator())); + opts.sort(Map.Entry.comparingByKey()); for (Map.Entry ent : opts) { data.addProperty(ent.getKey(), ent.getValue());