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 16335e7c..7ba69cb0 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -50,7 +50,6 @@ 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; -import me.lucko.luckperms.common.contexts.ContextManager; import me.lucko.luckperms.common.dependencies.Dependency; import me.lucko.luckperms.common.event.AbstractEventBus; import me.lucko.luckperms.common.managers.group.StandardGroupManager; @@ -93,7 +92,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { private StandardUserManager userManager; private StandardGroupManager groupManager; private StandardTrackManager trackManager; - private ContextManager contextManager; + private BukkitContextManager contextManager; private LPSubscriptionMap subscriptionMap; private LPPermissionMap permissionMap; private LPDefaultsMap defaultPermissionMap; @@ -375,7 +374,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { } @Override - public ContextManager getContextManager() { + public BukkitContextManager getContextManager() { return this.contextManager; } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/contexts/BukkitContextManager.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/contexts/BukkitContextManager.java index 92045825..cfe39bd0 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/contexts/BukkitContextManager.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/contexts/BukkitContextManager.java @@ -25,22 +25,78 @@ package me.lucko.luckperms.bukkit.contexts; +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.context.ImmutableContextSet; import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.contexts.ContextManager; +import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import org.bukkit.entity.Player; import java.util.EnumSet; +import java.util.concurrent.TimeUnit; public class BukkitContextManager extends ContextManager { + + // cache the creation of ContextsCache instances for online players with no expiry + private final LoadingCache> onlineSubjectCaches = Caffeine.newBuilder() + .build(key -> new ContextsCache<>(key, this)); + + // cache the creation of ContextsCache instances for offline players with a 1m expiry + private final LoadingCache> offlineSubjectCaches = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.MINUTES) + .build(key -> { + ContextsCache cache = this.onlineSubjectCaches.getIfPresent(key); + if (cache != null) { + return cache; + } + return new ContextsCache<>(key, this); + }); + public BukkitContextManager(LPBukkitPlugin plugin) { super(plugin, Player.class); } + public void onPlayerQuit(Player player) { + this.onlineSubjectCaches.invalidate(player); + } + + @Override + public ContextsSupplier getCacheFor(Player subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + if (subject.isOnline()) { + return this.onlineSubjectCaches.get(subject); + } else { + return this.offlineSubjectCaches.get(subject); + } + } + + @Override + public void invalidateCache(Player subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + ContextsCache cache = this.onlineSubjectCaches.getIfPresent(subject); + if (cache != null) { + cache.invalidate(); + } + + cache = this.offlineSubjectCaches.getIfPresent(subject); + if (cache != null) { + cache.invalidate(); + } + } + @Override public Contexts formContexts(Player subject, ImmutableContextSet contextSet) { EnumSet settings = this.plugin.getConfiguration().get(ConfigKeys.LOOKUP_SETTINGS); 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 d9174b11..12a3d69f 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 @@ -197,6 +197,9 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme user.clearTransientNodes(); } }); + + // remove their contexts cache + this.plugin.getContextManager().onPlayerQuit(player); } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissible.java index 1d72ee5b..80d49191 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissible.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissible.java @@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.common.config.ConfigKeys; -import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.common.verbose.CheckOrigin; @@ -91,7 +91,7 @@ public class LPPermissible extends PermissibleBase { private final LPBukkitPlugin plugin; // caches context lookups for the player - private final ContextsCache contextsCache; + private final ContextsSupplier contextsSupplier; // the players previous permissible. (the one they had before this one was injected) private PermissibleBase oldPermissible = null; @@ -108,7 +108,7 @@ public class LPPermissible extends PermissibleBase { this.user = Objects.requireNonNull(user, "user"); this.player = Objects.requireNonNull(player, "player"); this.plugin = Objects.requireNonNull(plugin, "plugin"); - this.contextsCache = plugin.getContextManager().getCacheFor(player); + this.contextsSupplier = plugin.getContextManager().getCacheFor(player); injectFakeAttachmentsList(); } @@ -137,7 +137,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK); return ts != Tristate.UNDEFINED || Permission.DEFAULT_PERMISSION.getValue(isOp()); } @@ -147,7 +147,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK); if (ts != Tristate.UNDEFINED) { return true; } @@ -165,7 +165,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK); return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp()); } @@ -175,7 +175,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK); if (ts != Tristate.UNDEFINED) { return ts.asBoolean(); } @@ -205,7 +205,7 @@ public class LPPermissible extends PermissibleBase { @Override public Set getEffectivePermissions() { - return this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet().stream() + return this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getImmutableBacking().entrySet().stream() .map(entry -> new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue())) .collect(ImmutableCollectors.toSet()); } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/contexts/BungeeContextManager.java b/bungee/src/main/java/me/lucko/luckperms/bungee/contexts/BungeeContextManager.java index ade800eb..f0972c7c 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/contexts/BungeeContextManager.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/contexts/BungeeContextManager.java @@ -25,20 +25,75 @@ package me.lucko.luckperms.bungee.contexts; +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.context.ImmutableContextSet; import me.lucko.luckperms.bungee.LPBungeePlugin; import me.lucko.luckperms.common.contexts.ContextManager; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import net.md_5.bungee.api.connection.ProxiedPlayer; +import java.util.concurrent.TimeUnit; + public class BungeeContextManager extends ContextManager { + + private final LoadingCache contextsCache = Caffeine.newBuilder() + .expireAfterWrite(50, TimeUnit.MILLISECONDS) + .build(this::calculate); + public BungeeContextManager(LPBungeePlugin plugin) { super(plugin, ProxiedPlayer.class); } + @Override + public ContextsSupplier getCacheFor(ProxiedPlayer subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + return new InlineContextsSupplier(subject, this.contextsCache); + } + + @Override + public ImmutableContextSet getApplicableContext(ProxiedPlayer subject) { + return getApplicableContexts(subject).getContexts().makeImmutable(); + } + + @Override + public Contexts getApplicableContexts(ProxiedPlayer subject) { + return this.contextsCache.get(subject); + } + + @Override + public void invalidateCache(ProxiedPlayer subject) { + this.contextsCache.invalidate(subject); + } + @Override public Contexts formContexts(ProxiedPlayer subject, ImmutableContextSet contextSet) { return formContexts(contextSet); } + + private static final class InlineContextsSupplier implements ContextsSupplier { + private final ProxiedPlayer key; + private final LoadingCache contextsCache; + + private InlineContextsSupplier(ProxiedPlayer key, LoadingCache contextsCache) { + this.key = key; + this.contextsCache = contextsCache; + } + + @Override + public Contexts getContexts() { + return this.contextsCache.get(this.key); + } + + @Override + public ImmutableContextSet getContextSet() { + return getContexts().getContexts().makeImmutable(); + } + } } diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java index 6f5edd91..e83ed8d9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java @@ -25,8 +25,6 @@ package me.lucko.luckperms.common.contexts; -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Contexts; @@ -62,12 +60,6 @@ public abstract class ContextManager { private final List> calculators = new CopyOnWriteArrayList<>(); private final List staticCalculators = new CopyOnWriteArrayList<>(); - // caches the creation of cache instances. cache-ception. - // we want to encourage re-use of these instances, it's faster that way - private final LoadingCache> subjectCaches = Caffeine.newBuilder() - .weakKeys() - .build(key -> new ContextsCache<>(key, this)); - // caches static context lookups private final StaticLookupCache staticLookupCache = new StaticLookupCache(); @@ -129,12 +121,7 @@ public abstract class ContextManager { * @param subject the subject * @return the cache */ - public ContextsCache getCacheFor(T subject) { - if (subject == null) { - throw new NullPointerException("subject"); - } - return this.subjectCaches.get(subject); - } + public abstract ContextsSupplier getCacheFor(T subject); /** * Gets the contexts from the static calculators in this manager. @@ -228,18 +215,9 @@ public abstract class ContextManager { * * @param subject the subject */ - public void invalidateCache(T subject) { - if (subject == null) { - throw new NullPointerException("subject"); - } + public abstract void invalidateCache(T subject); - ContextsCache cache = this.subjectCaches.getIfPresent(subject); - if (cache != null) { - cache.invalidate(); - } - } - - Contexts calculate(T subject) { + protected Contexts calculate(T subject) { MutableContextSet accumulator = MutableContextSet.create(); for (ContextCalculator calculator : ContextManager.this.calculators) { diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsCache.java b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsCache.java index cdc5c24e..c8f5914f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsCache.java @@ -34,12 +34,11 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; /** - * Extension of {@link ContextManager} that implements an expiring lookup cache - * per player. + * Implementation of {@link ContextsSupplier} that caches results. * * @param the player type */ -public final class ContextsCache extends ExpiringCache { +public final class ContextsCache extends ExpiringCache implements ContextsSupplier { private final T subject; private final ContextManager contextManager; @@ -55,10 +54,12 @@ public final class ContextsCache extends ExpiringCache { return this.contextManager.calculate(this.subject); } + @Override public Contexts getContexts() { return get(); } + @Override public ImmutableContextSet getContextSet() { // this is actually already immutable, but the Contexts method signature returns the interface. // using the makeImmutable method is faster than casting diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsSupplier.java b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsSupplier.java new file mode 100644 index 00000000..53caec97 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextsSupplier.java @@ -0,0 +1,40 @@ +/* + * 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.contexts; + +import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.context.ImmutableContextSet; + +/** + * Supplies contexts for a given subject. + */ +public interface ContextsSupplier { + + Contexts getContexts(); + + ImmutableContextSet getContextSet(); + +} 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 6032cead..db83ef65 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java @@ -34,7 +34,6 @@ 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; -import me.lucko.luckperms.common.contexts.ContextManager; import me.lucko.luckperms.common.dependencies.Dependency; import me.lucko.luckperms.common.event.AbstractEventBus; import me.lucko.luckperms.common.managers.group.StandardGroupManager; @@ -90,7 +89,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { private StandardUserManager userManager; private StandardGroupManager groupManager; private StandardTrackManager trackManager; - private ContextManager contextManager; + private NukkitContextManager contextManager; private LPSubscriptionMap subscriptionMap; private LPPermissionMap permissionMap; private LPDefaultsMap defaultPermissionMap; @@ -339,7 +338,7 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { } @Override - public ContextManager getContextManager() { + public NukkitContextManager getContextManager() { return this.contextManager; } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/contexts/NukkitContextManager.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/contexts/NukkitContextManager.java index 0eba4c29..d5ac71a4 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/contexts/NukkitContextManager.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/contexts/NukkitContextManager.java @@ -25,22 +25,78 @@ package me.lucko.luckperms.nukkit.contexts; +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.context.ImmutableContextSet; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.contexts.ContextManager; +import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.nukkit.LPNukkitPlugin; import cn.nukkit.Player; import java.util.EnumSet; +import java.util.concurrent.TimeUnit; public class NukkitContextManager extends ContextManager { + + // cache the creation of ContextsCache instances for online players with no expiry + private final LoadingCache> onlineSubjectCaches = Caffeine.newBuilder() + .build(key -> new ContextsCache<>(key, this)); + + // cache the creation of ContextsCache instances for offline players with a 1m expiry + private final LoadingCache> offlineSubjectCaches = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.MINUTES) + .build(key -> { + ContextsCache cache = this.onlineSubjectCaches.getIfPresent(key); + if (cache != null) { + return cache; + } + return new ContextsCache<>(key, this); + }); + public NukkitContextManager(LPNukkitPlugin plugin) { super(plugin, Player.class); } + public void onPlayerQuit(Player player) { + this.onlineSubjectCaches.invalidate(player); + } + + @Override + public ContextsSupplier getCacheFor(Player subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + if (subject.isOnline()) { + return this.onlineSubjectCaches.get(subject); + } else { + return this.offlineSubjectCaches.get(subject); + } + } + + @Override + public void invalidateCache(Player subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + ContextsCache cache = this.onlineSubjectCaches.getIfPresent(subject); + if (cache != null) { + cache.invalidate(); + } + + cache = this.offlineSubjectCaches.getIfPresent(subject); + if (cache != null) { + cache.invalidate(); + } + } + @Override public Contexts formContexts(Player subject, ImmutableContextSet contextSet) { EnumSet settings = this.plugin.getConfiguration().get(ConfigKeys.LOOKUP_SETTINGS); 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 6c7d43c5..597cf5ed 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 @@ -189,6 +189,9 @@ public class NukkitConnectionListener extends AbstractConnectionListener impleme user.clearTransientNodes(); } }); + + // remove their contexts cache + this.plugin.getContextManager().onPlayerQuit(player); } } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissible.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissible.java index 6732aadc..7bbcfcd3 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissible.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissible.java @@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.common.config.ConfigKeys; -import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.common.verbose.CheckOrigin; @@ -91,7 +91,7 @@ public class LPPermissible extends PermissibleBase { private final LPNukkitPlugin plugin; // caches context lookups for the player - private final ContextsCache contextsCache; + private final ContextsSupplier contextsSupplier; // the players previous permissible. (the one they had before this one was injected) private PermissibleBase oldPermissible = null; @@ -108,7 +108,7 @@ public class LPPermissible extends PermissibleBase { this.user = Objects.requireNonNull(user, "user"); this.player = Objects.requireNonNull(player, "player"); this.plugin = Objects.requireNonNull(plugin, "plugin"); - this.contextsCache = plugin.getContextManager().getCacheFor(player); + this.contextsSupplier = plugin.getContextManager().getCacheFor(player); injectFakeAttachmentsList(); } @@ -137,7 +137,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_LOOKUP_CHECK); return ts != Tristate.UNDEFINED || PermissionDefault.OP.getValue(isOp()); } @@ -147,7 +147,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_LOOKUP_CHECK); if (ts != Tristate.UNDEFINED) { return true; } @@ -166,7 +166,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission, CheckOrigin.PLATFORM_PERMISSION_CHECK); return ts != Tristate.UNDEFINED ? ts.asBoolean() : PermissionDefault.OP.getValue(isOp()); } @@ -176,7 +176,7 @@ public class LPPermissible extends PermissibleBase { throw new NullPointerException("permission"); } - Tristate ts = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK); + Tristate ts = this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getPermissionValue(permission.getName(), CheckOrigin.PLATFORM_PERMISSION_CHECK); if (ts != Tristate.UNDEFINED) { return ts.asBoolean(); } @@ -207,7 +207,7 @@ public class LPPermissible extends PermissibleBase { @Override public Map getEffectivePermissions() { - return this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet().stream() + return this.user.getCachedData().getPermissionData(this.contextsSupplier.getContexts()).getImmutableBacking().entrySet().stream() .collect(ImmutableCollectors.toMap(Map.Entry::getKey, entry -> new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()))); } diff --git a/sponge/sponge-service-api6/src/main/java/me/lucko/luckperms/sponge/service/proxy/api6/SubjectProxy.java b/sponge/sponge-service-api6/src/main/java/me/lucko/luckperms/sponge/service/proxy/api6/SubjectProxy.java index 5f6bae14..7393f3af 100644 --- a/sponge/sponge-service-api6/src/main/java/me/lucko/luckperms/sponge/service/proxy/api6/SubjectProxy.java +++ b/sponge/sponge-service-api6/src/main/java/me/lucko/luckperms/sponge/service/proxy/api6/SubjectProxy.java @@ -27,7 +27,7 @@ package me.lucko.luckperms.sponge.service.proxy.api6; import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.common.contexts.ContextManager; -import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.sponge.service.CompatibilityUtil; import me.lucko.luckperms.sponge.service.model.LPPermissionService; @@ -54,7 +54,7 @@ public final class SubjectProxy implements Subject, ProxiedSubject { private final LPPermissionService service; private final LPSubjectReference ref; - private ContextsCache contextsCache = null; + private ContextsSupplier contextsSupplier = null; public SubjectProxy(LPPermissionService service, LPSubjectReference ref) { this.service = service; @@ -66,12 +66,12 @@ public final class SubjectProxy implements Subject, ProxiedSubject { } // lazy init - private ContextsCache getContextsCache() { - if (this.contextsCache == null) { + private ContextsSupplier getContextsCache() { + if (this.contextsSupplier == null) { ContextManager contextManager = (ContextManager) this.service.getPlugin().getContextManager(); - this.contextsCache = contextManager.getCacheFor(this); + this.contextsSupplier = contextManager.getCacheFor(this); } - return this.contextsCache; + return this.contextsSupplier; } @Nonnull diff --git a/sponge/sponge-service-api7/src/main/java/me/lucko/luckperms/sponge/service/proxy/api7/SubjectProxy.java b/sponge/sponge-service-api7/src/main/java/me/lucko/luckperms/sponge/service/proxy/api7/SubjectProxy.java index 9b192345..f62a46ba 100644 --- a/sponge/sponge-service-api7/src/main/java/me/lucko/luckperms/sponge/service/proxy/api7/SubjectProxy.java +++ b/sponge/sponge-service-api7/src/main/java/me/lucko/luckperms/sponge/service/proxy/api7/SubjectProxy.java @@ -27,7 +27,7 @@ package me.lucko.luckperms.sponge.service.proxy.api7; import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.common.contexts.ContextManager; -import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.sponge.service.CompatibilityUtil; import me.lucko.luckperms.sponge.service.model.LPPermissionService; import me.lucko.luckperms.sponge.service.model.LPSubject; @@ -54,7 +54,7 @@ public final class SubjectProxy implements Subject, ProxiedSubject { private final LPPermissionService service; private final LPSubjectReference ref; - private ContextsCache contextsCache; + private ContextsSupplier contextsSupplier; public SubjectProxy(LPPermissionService service, LPSubjectReference ref) { this.service = service; @@ -66,12 +66,12 @@ public final class SubjectProxy implements Subject, ProxiedSubject { } // lazy init - private ContextsCache getContextsCache() { - if (this.contextsCache == null) { + private ContextsSupplier getContextsCache() { + if (this.contextsSupplier == null) { ContextManager contextManager = (ContextManager) this.service.getPlugin().getContextManager(); - this.contextsCache = contextManager.getCacheFor(this); + this.contextsSupplier = contextManager.getCacheFor(this); } - return this.contextsCache; + return this.contextsSupplier; } @Nonnull diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/contexts/SpongeContextManager.java b/sponge/src/main/java/me/lucko/luckperms/sponge/contexts/SpongeContextManager.java index 5ff5c59d..806488f1 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/contexts/SpongeContextManager.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/contexts/SpongeContextManager.java @@ -25,18 +25,51 @@ package me.lucko.luckperms.sponge.contexts; +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.context.ImmutableContextSet; import me.lucko.luckperms.common.contexts.ContextManager; +import me.lucko.luckperms.common.contexts.ContextsCache; +import me.lucko.luckperms.common.contexts.ContextsSupplier; import me.lucko.luckperms.sponge.LPSpongePlugin; import org.spongepowered.api.service.permission.Subject; +import java.util.concurrent.TimeUnit; + public class SpongeContextManager extends ContextManager { + + private final LoadingCache> subjectCaches = Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.MINUTES) + .build(key -> new ContextsCache<>(key, this)); + public SpongeContextManager(LPSpongePlugin plugin) { super(plugin, Subject.class); } + @Override + public ContextsSupplier getCacheFor(Subject subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + return subjectCaches.get(subject); + } + + @Override + public void invalidateCache(Subject subject) { + if (subject == null) { + throw new NullPointerException("subject"); + } + + ContextsCache cache = this.subjectCaches.getIfPresent(subject); + if (cache != null) { + cache.invalidate(); + } + } + @Override public Contexts formContexts(Subject subject, ImmutableContextSet contextSet) { return formContexts(contextSet);