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 79ebc7b1d..a417371b1 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -53,6 +53,7 @@ import me.lucko.luckperms.common.utils.LocaleManager; import me.lucko.luckperms.common.utils.LogFactory; import me.lucko.luckperms.sponge.contexts.WorldCalculator; import me.lucko.luckperms.sponge.service.LuckPermsService; +import me.lucko.luckperms.sponge.timings.LPTimings; import me.lucko.luckperms.sponge.utils.VersionData; import org.slf4j.Logger; import org.spongepowered.api.Game; @@ -102,6 +103,7 @@ public class LPSpongePlugin implements LuckPermsPlugin { private Path configDir; private Scheduler scheduler = Sponge.getScheduler(); + private LPTimings timings; private final Set ignoringLogs = ConcurrentHashMap.newKeySet(); private LPConfiguration configuration; @@ -126,6 +128,7 @@ public class LPSpongePlugin implements LuckPermsPlugin { public void onEnable(GamePreInitializationEvent event) { log = LogFactory.wrap(logger); debugHandler = new DebugHandler(); + timings = new LPTimings(this); getLog().info("Loading configuration..."); configuration = new SpongeConfig(this); diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java index af8dc4072..4748db496 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java @@ -22,12 +22,13 @@ package me.lucko.luckperms.sponge; +import co.aikar.timings.Timing; import com.google.common.base.Splitter; import me.lucko.luckperms.api.data.Callback; -import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.commands.CommandManager; import me.lucko.luckperms.common.commands.Util; import me.lucko.luckperms.common.constants.Patterns; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.command.CommandCallable; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -42,28 +43,37 @@ import java.util.Optional; @SuppressWarnings("NullableProblems") class SpongeCommand extends CommandManager implements CommandCallable { - SpongeCommand(LuckPermsPlugin plugin) { + private final LPSpongePlugin plugin; + + SpongeCommand(LPSpongePlugin plugin) { super(plugin); + this.plugin = plugin; } @Override public CommandResult process(CommandSource source, String s) throws CommandException { - onCommand( - SpongeSenderFactory.get(getPlugin()).wrap(source), - "perms", - Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(s)), - Callback.empty() - ); - return CommandResult.success(); + try (Timing ignored = plugin.getTimings().time(LPTiming.ON_COMMAND)) { + onCommand( + SpongeSenderFactory.get(getPlugin()).wrap(source), + "perms", + Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(s)), + Callback.empty() + ); + return CommandResult.success(); + } } @Override public List getSuggestions(CommandSource source, String s, @Nullable Location location) throws CommandException { - return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + try (Timing ignored = plugin.getTimings().time(LPTiming.COMMAND_TAB_COMPLETE)) { + return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + } } public List getSuggestions(CommandSource source, String s) throws CommandException { - return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + try (Timing ignored = plugin.getTimings().time(LPTiming.COMMAND_TAB_COMPLETE)) { + return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + } } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeListener.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeListener.java index 1d815b7db..80f9cc09b 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeListener.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeListener.java @@ -22,11 +22,13 @@ package me.lucko.luckperms.sponge; +import co.aikar.timings.Timing; import me.lucko.luckperms.api.caching.UserData; import me.lucko.luckperms.api.context.MutableContextSet; import me.lucko.luckperms.common.constants.Message; import me.lucko.luckperms.common.users.User; import me.lucko.luckperms.common.utils.AbstractListener; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Order; @@ -63,36 +65,38 @@ public class SpongeListener extends AbstractListener { @SuppressWarnings("deprecation") @Listener(order = Order.EARLY) public void onClientLogin(ClientConnectionEvent.Login e) { - final GameProfile player = e.getProfile(); - final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId())); + try (Timing ignored = plugin.getTimings().time(LPTiming.ON_CLIENT_LOGIN)) { + final GameProfile player = e.getProfile(); + final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId())); - // Check if the user was loaded successfully. - if (user == null) { - e.setCancelled(true); - e.setMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(Message.LOADING_ERROR.toString())); - return; - } + // Check if the user was loaded successfully. + if (user == null) { + e.setCancelled(true); + e.setMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(Message.LOADING_ERROR.toString())); + return; + } - // Attempt to pre-process some permissions for the user to save time later. Might not work, but it's better than nothing. - Optional p = e.getCause().first(Player.class); - if (p.isPresent()) { - MutableContextSet context = MutableContextSet.fromSet(plugin.getContextManager().getApplicableContext(p.get())); + // Attempt to pre-process some permissions for the user to save time later. Might not work, but it's better than nothing. + Optional p = e.getCause().first(Player.class); + if (p.isPresent()) { + MutableContextSet context = MutableContextSet.fromSet(plugin.getContextManager().getApplicableContext(p.get())); - List worlds = plugin.getGame().getServer().getWorlds().stream() - .map(World::getName) - .collect(Collectors.toList()); + List worlds = plugin.getGame().getServer().getWorlds().stream() + .map(World::getName) + .collect(Collectors.toList()); - plugin.doAsync(() -> { - UserData data = user.getUserData(); - data.preCalculate(plugin.getService().calculateContexts(context)); + plugin.doAsync(() -> { + UserData data = user.getUserData(); + data.preCalculate(plugin.getService().calculateContexts(context)); - for (String world : worlds) { - MutableContextSet modified = MutableContextSet.fromSet(context); - modified.removeAll("world"); - modified.add("world", world); - data.preCalculate(plugin.getService().calculateContexts(modified)); - } - }); + for (String world : worlds) { + MutableContextSet modified = MutableContextSet.fromSet(context); + modified.removeAll("world"); + modified.add("world", world); + data.preCalculate(plugin.getService().calculateContexts(modified)); + } + }); + } } } @@ -104,7 +108,9 @@ public class SpongeListener extends AbstractListener { @Listener(order = Order.LAST) public void onClientLeave(ClientConnectionEvent.Disconnect e) { - onLeave(e.getTargetEntity().getUniqueId()); - plugin.getService().getUserSubjects().unload(plugin.getUuidCache().getUUID(e.getTargetEntity().getUniqueId())); + try (Timing ignored = plugin.getTimings().time(LPTiming.ON_CLIENT_LEAVE)) { + onLeave(e.getTargetEntity().getUniqueId()); + plugin.getService().getUserSubjects().unload(plugin.getUuidCache().getUUID(e.getTargetEntity().getUniqueId())); + } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsGroupSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsGroupSubject.java index 05654173c..55446ac0a 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsGroupSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsGroupSubject.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service; +import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; import lombok.AccessLevel; import lombok.EqualsAndHashCode; @@ -30,6 +31,7 @@ import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.groups.Group; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.service.permission.NodeTree; import org.spongepowered.api.service.permission.Subject; @@ -81,72 +83,82 @@ public class LuckPermsGroupSubject extends LuckPermsSubject { @Override public Tristate getPermissionValue(ContextSet contexts, String permission) { - Map permissions = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream() - .map(LocalizedNode::getNode) - .collect(Collectors.toMap(Node::getPermission, Node::getValue)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_PERMISSION_VALUE)) { + Map permissions = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream() + .map(LocalizedNode::getNode) + .collect(Collectors.toMap(Node::getPermission, Node::getValue)); - Tristate t = NodeTree.of(permissions).get(permission); - if (t != Tristate.UNDEFINED) { + Tristate t = NodeTree.of(permissions).get(permission); + if (t != Tristate.UNDEFINED) { + return t; + } + + t = service.getGroupSubjects().getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission); + if (t != Tristate.UNDEFINED) { + return t; + } + + t = service.getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission); return t; } - - t = service.getGroupSubjects().getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission); - if (t != Tristate.UNDEFINED) { - return t; - } - - t = service.getDefaults().getPermissionValue(LuckPermsService.convertContexts(contexts), permission); - return t; } @Override public boolean isChildOf(ContextSet contexts, Subject parent) { - return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_IS_CHILD_OF)) { + return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); + } } @Override public List getParents(ContextSet contexts) { - List subjects = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream() - .map(LocalizedNode::getNode) - .filter(Node::isGroupNode) - .map(Node::getGroupName) - .map(s -> service.getGroupSubjects().get(s)) - .collect(Collectors.toList()); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_PARENTS)) { + List subjects = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream() + .map(LocalizedNode::getNode) + .filter(Node::isGroupNode) + .map(Node::getGroupName) + .map(s -> service.getGroupSubjects().get(s)) + .collect(Collectors.toList()); - subjects.addAll(service.getGroupSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts))); - subjects.addAll(service.getDefaults().getParents(LuckPermsService.convertContexts(contexts))); + subjects.addAll(service.getGroupSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts))); + subjects.addAll(service.getDefaults().getParents(LuckPermsService.convertContexts(contexts))); - return ImmutableList.copyOf(subjects); + return ImmutableList.copyOf(subjects); + } } @Override public Optional getOption(ContextSet contexts, String s) { - Optional option; - if (s.equalsIgnoreCase("prefix")) { - option = getChatMeta(contexts, true); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_OPTION)) { + Optional option; + if (s.equalsIgnoreCase("prefix")) { + option = getChatMeta(contexts, true); - } else if (s.equalsIgnoreCase("suffix")) { - option = getChatMeta(contexts, false); + } else if (s.equalsIgnoreCase("suffix")) { + option = getChatMeta(contexts, false); - } else { - option = getMeta(contexts, s); + } else { + option = getMeta(contexts, s); + } + + if (option.isPresent()) { + return option; + } + + option = service.getGroupSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); + if (option.isPresent()) { + return option; + } + + return service.getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); } - - if (option.isPresent()) { - return option; - } - - option = service.getGroupSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); - if (option.isPresent()) { - return option; - } - - return service.getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); } @Override public ContextSet getActiveContextSet() { - return service.getPlugin().getContextManager().getApplicableContext(this); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_ACTIVE_CONTEXTS)) { + return service.getPlugin().getContextManager().getApplicableContext(this); + } } private Optional getChatMeta(ContextSet contexts, boolean prefix) { 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 18387374b..a5df222ac 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 @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service; +import co.aikar.timings.Timing; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -38,6 +39,7 @@ import me.lucko.luckperms.sponge.service.collections.UserCollection; import me.lucko.luckperms.sponge.service.persisted.PersistedCollection; import me.lucko.luckperms.sponge.service.persisted.SubjectStorage; import me.lucko.luckperms.sponge.service.simple.SimpleCollection; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.context.ContextCalculator; @@ -101,7 +103,9 @@ public class LuckPermsService implements PermissionService { @Override public SubjectCollection getSubjects(String s) { - return collections.getUnchecked(s.toLowerCase()); + try (Timing ignored = plugin.getTimings().time(LPTiming.GET_SUBJECTS)) { + return collections.getUnchecked(s.toLowerCase()); + } } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java index 2479f61e1..ece61df83 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service; +import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -34,6 +35,7 @@ import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.users.User; import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; import me.lucko.luckperms.exceptions.ObjectLacksException; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.SubjectData; @@ -63,437 +65,448 @@ public class LuckPermsSubjectData implements SubjectData { @Override public Map, Map> getAllPermissions() { - Map, Map> perms = new HashMap<>(); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_PERMISSIONS)) { + Map, Map> perms = new HashMap<>(); - for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { - Set contexts = LuckPermsService.convertContexts(n.getContexts()); + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + Set contexts = LuckPermsService.convertContexts(n.getContexts()); - if (n.isServerSpecific()) { - contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!perms.containsKey(contexts)) { + perms.put(contexts, new HashMap<>()); + } + + perms.get(contexts).put(n.getPermission(), n.getValue()); } - if (n.isWorldSpecific()) { - contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + ImmutableMap.Builder, Map> map = ImmutableMap.builder(); + for (Map.Entry, Map> e : perms.entrySet()) { + map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue())); } - - if (!perms.containsKey(contexts)) { - perms.put(contexts, new HashMap<>()); - } - - perms.get(contexts).put(n.getPermission(), n.getValue()); + return map.build(); } - - ImmutableMap.Builder, Map> map = ImmutableMap.builder(); - for (Map.Entry, Map> e : perms.entrySet()) { - map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue())); - } - return map.build(); } @Override public Map getPermissions(Set contexts) { - ImmutableMap.Builder permissions = ImmutableMap.builder(); - - (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(n -> n.shouldApplyWithContext(LuckPermsService.convertContexts(contexts), true)) - .forEach(n -> permissions.put(n.getKey(), n.getValue())); - - return permissions.build(); + return getAllPermissions().getOrDefault(contexts, ImmutableMap.of()); } @Override - public boolean setPermission(Set set, String s, Tristate tristate) { - if (tristate == Tristate.UNDEFINED) { - // Unset - Node.Builder builder = new me.lucko.luckperms.common.core.Node.Builder(s); + public boolean setPermission(Set contexts, String permission, Tristate tristate) { + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_PERMISSION)) { + if (tristate == Tristate.UNDEFINED) { + // Unset + Node.Builder builder = new me.lucko.luckperms.common.core.Node.Builder(permission); - for (Context ct : set) { + for (Context ct : contexts) { + builder.withExtraContext(ct.getKey(), ct.getValue()); + } + + try { + if (enduring) { + holder.unsetPermission(builder.build()); + } else { + holder.unsetTransientPermission(builder.build()); + } + } catch (ObjectLacksException ignored) {} + + objectSave(holder); + return true; + } + + Node.Builder builder = new me.lucko.luckperms.common.core.Node.Builder(permission) + .setValue(tristate.asBoolean()); + + for (Context ct : contexts) { builder.withExtraContext(ct.getKey(), ct.getValue()); } try { if (enduring) { - holder.unsetPermission(builder.build()); + holder.setPermission(builder.build()); } else { - holder.unsetTransientPermission(builder.build()); - } - } catch (ObjectLacksException ignored) {} - - objectSave(holder); - return true; - } - - Node.Builder builder = new me.lucko.luckperms.common.core.Node.Builder(s) - .setValue(tristate.asBoolean()); - - for (Context ct : set) { - builder.withExtraContext(ct.getKey(), ct.getValue()); - } - - try { - if (enduring) { - holder.setPermission(builder.build()); - } else { - holder.setTransientPermission(builder.build()); - } - } catch (ObjectAlreadyHasException ignored) {} - - objectSave(holder); - return true; - } - - @Override - public boolean clearPermissions() { - if (enduring) { - holder.clearNodes(); - } else { - holder.clearTransientNodes(); - } - objectSave(holder); - return true; - } - - @Override - public boolean clearPermissions(Set contexts) { - List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(node -> node.shouldApplyWithContext(LuckPermsService.convertContexts(contexts))) - .collect(Collectors.toList()); - - toRemove.forEach(n -> { - try { - if (enduring) { - holder.unsetPermission(n); - } else { - holder.unsetTransientPermission(n); - } - } catch (ObjectLacksException ignored) {} - }); - - if (holder instanceof User) { - service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); - } - - objectSave(holder); - return !toRemove.isEmpty(); - } - - @Override - public Map, List> getAllParents() { - Map, List> parents = new HashMap<>(); - - for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { - if (!n.isGroupNode()) { - continue; - } - - Set contexts = LuckPermsService.convertContexts(n.getContexts()); - - if (n.isServerSpecific()) { - contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); - } - - if (n.isWorldSpecific()) { - contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); - } - - if (!parents.containsKey(contexts)) { - parents.put(contexts, new ArrayList<>()); - } - - parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName())); - } - - ImmutableMap.Builder, List> map = ImmutableMap.builder(); - for (Map.Entry, List> e : parents.entrySet()) { - map.put(ImmutableSet.copyOf(e.getKey()), ImmutableList.copyOf(e.getValue())); - } - return map.build(); - } - - @Override - public List getParents(Set contexts) { - ImmutableList.Builder parents = ImmutableList.builder(); - - (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(Node::isGroupNode) - .filter(n -> n.shouldApplyWithContext(LuckPermsService.convertContexts(contexts), true)) - .forEach(n -> parents.add(service.getGroupSubjects().get(n.getGroupName()))); - - return parents.build(); - } - - @Override - public boolean addParent(Set set, Subject subject) { - if (subject instanceof LuckPermsGroupSubject) { - LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); - ContextSet contexts = LuckPermsService.convertContexts(set); - - try { - if (enduring) { - holder.setPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) - .withExtraContext(contexts) - .build()); - } else { - holder.setTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) - .withExtraContext(contexts) - .build()); + holder.setTransientPermission(builder.build()); } } catch (ObjectAlreadyHasException ignored) {} objectSave(holder); return true; } - return false; + } + + @Override + public boolean clearPermissions() { + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PERMISSIONS)) { + if (enduring) { + holder.clearNodes(); + } else { + holder.clearTransientNodes(); + } + objectSave(holder); + return true; + } + } + + @Override + public boolean clearPermissions(Set c) { + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PERMISSIONS)) { + List toRemove = new ArrayList<>(); + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + Set contexts = LuckPermsService.convertContexts(n.getContexts()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (contexts.equals(c)) { + toRemove.add(n); + } + } + + toRemove.forEach(n -> { + try { + if (enduring) { + holder.unsetPermission(n); + } else { + holder.unsetTransientPermission(n); + } + } catch (ObjectLacksException ignored) {} + }); + + if (holder instanceof User) { + service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); + } + + objectSave(holder); + return !toRemove.isEmpty(); + } + } + + @Override + public Map, List> getAllParents() { + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_PARENTS)) { + Map, List> parents = new HashMap<>(); + + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + if (!n.isGroupNode()) { + continue; + } + + Set contexts = LuckPermsService.convertContexts(n.getContexts()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!parents.containsKey(contexts)) { + parents.put(contexts, new ArrayList<>()); + } + + parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName())); + } + + ImmutableMap.Builder, List> map = ImmutableMap.builder(); + for (Map.Entry, List> e : parents.entrySet()) { + map.put(ImmutableSet.copyOf(e.getKey()), ImmutableList.copyOf(e.getValue())); + } + return map.build(); + } + } + + @Override + public List getParents(Set contexts) { + return getAllParents().getOrDefault(contexts, ImmutableList.of()); + } + + @Override + public boolean addParent(Set set, Subject subject) { + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_ADD_PARENT)) { + if (subject instanceof LuckPermsGroupSubject) { + LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); + ContextSet contexts = LuckPermsService.convertContexts(set); + + try { + if (enduring) { + holder.setPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } else { + holder.setTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } + } catch (ObjectAlreadyHasException ignored) {} + + objectSave(holder); + return true; + } + return false; + } } @Override public boolean removeParent(Set set, Subject subject) { - if (subject instanceof LuckPermsGroupSubject) { - LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); - ContextSet contexts = LuckPermsService.convertContexts(set); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_REMOVE_PARENT)) { + if (subject instanceof LuckPermsGroupSubject) { + LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); + ContextSet contexts = LuckPermsService.convertContexts(set); - try { - if (enduring) { - holder.unsetPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) - .withExtraContext(contexts) - .build()); - } else { - holder.unsetTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) - .withExtraContext(contexts) - .build()); - } - } catch (ObjectLacksException ignored) {} + try { + if (enduring) { + holder.unsetPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } else { + holder.unsetTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } + } catch (ObjectLacksException ignored) {} - objectSave(holder); - return true; + objectSave(holder); + return true; + } + return false; } - return false; } @Override public boolean clearParents() { - List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(Node::isGroupNode) - .collect(Collectors.toList()); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PARENTS)) { + List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() + .filter(Node::isGroupNode) + .collect(Collectors.toList()); - toRemove.forEach(n -> { - try { - if (enduring) { - holder.unsetPermission(n); - } else { - holder.unsetTransientPermission(n); - } - } catch (ObjectLacksException ignored) {} - }); + toRemove.forEach(n -> { + try { + if (enduring) { + holder.unsetPermission(n); + } else { + holder.unsetTransientPermission(n); + } + } catch (ObjectLacksException ignored) {} + }); - if (holder instanceof User) { - service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); + if (holder instanceof User) { + service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); + } + + objectSave(holder); + return !toRemove.isEmpty(); } - - objectSave(holder); - return !toRemove.isEmpty(); } @Override public boolean clearParents(Set set) { - ContextSet context = LuckPermsService.convertContexts(set); - - List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(Node::isGroupNode) - .filter(node -> node.shouldApplyWithContext(context)) - .collect(Collectors.toList()); - - toRemove.forEach(n -> { - try { - if (enduring) { - holder.unsetPermission(n); - } else { - holder.unsetTransientPermission(n); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PARENTS)) { + List toRemove = new ArrayList<>(); + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + if (!n.isGroupNode()) { + continue; } - } catch (ObjectLacksException ignored) {} - }); - if (holder instanceof User) { - service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); + Set contexts = LuckPermsService.convertContexts(n.getContexts()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (contexts.equals(set)) { + toRemove.add(n); + } + } + + toRemove.forEach(n -> { + try { + if (enduring) { + holder.unsetPermission(n); + } else { + holder.unsetTransientPermission(n); + } + } catch (ObjectLacksException ignored) {} + }); + + if (holder instanceof User) { + service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); + } + + objectSave(holder); + return !toRemove.isEmpty(); } - - objectSave(holder); - return !toRemove.isEmpty(); } @Override public Map, Map> getAllOptions() { - Map, Map> options = new HashMap<>(); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_OPTIONS)) { + Map, Map> options = new HashMap<>(); - int prefixPriority = Integer.MIN_VALUE; - int suffixPriority = Integer.MIN_VALUE; + int prefixPriority = Integer.MIN_VALUE; + int suffixPriority = Integer.MIN_VALUE; - for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { - if (!n.getValue()) { - continue; - } - - if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) { - continue; - } - - Set contexts = LuckPermsService.convertContexts(n.getContexts()); - - if (n.isServerSpecific()) { - contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); - } - - if (n.isWorldSpecific()) { - contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); - } - - if (!options.containsKey(contexts)) { - options.put(contexts, new HashMap<>()); - } - - if (n.isPrefix()) { - Map.Entry value = n.getPrefix(); - if (value.getKey() > prefixPriority) { - options.get(contexts).put("prefix", value.getValue()); - prefixPriority = value.getKey(); + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + if (!n.getValue()) { + continue; } - continue; - } - if (n.isSuffix()) { - Map.Entry value = n.getSuffix(); - if (value.getKey() > suffixPriority) { - options.get(contexts).put("suffix", value.getValue()); - suffixPriority = value.getKey(); + if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) { + continue; + } + + Set contexts = LuckPermsService.convertContexts(n.getContexts()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!options.containsKey(contexts)) { + options.put(contexts, new HashMap<>()); + } + + if (n.isPrefix()) { + Map.Entry value = n.getPrefix(); + if (value.getKey() > prefixPriority) { + options.get(contexts).put("prefix", value.getValue()); + prefixPriority = value.getKey(); + } + continue; + } + + if (n.isSuffix()) { + Map.Entry value = n.getSuffix(); + if (value.getKey() > suffixPriority) { + options.get(contexts).put("suffix", value.getValue()); + suffixPriority = value.getKey(); + } + continue; + } + + if (n.isMeta()) { + Map.Entry meta = n.getMeta(); + options.get(contexts).put(meta.getKey(), meta.getValue()); } - continue; } - if (n.isMeta()) { - Map.Entry meta = n.getMeta(); - options.get(contexts).put(meta.getKey(), meta.getValue()); + ImmutableMap.Builder, Map> map = ImmutableMap.builder(); + for (Map.Entry, Map> e : options.entrySet()) { + map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue())); } + return map.build(); } - - ImmutableMap.Builder, Map> map = ImmutableMap.builder(); - for (Map.Entry, Map> e : options.entrySet()) { - map.put(ImmutableSet.copyOf(e.getKey()), ImmutableMap.copyOf(e.getValue())); - } - return map.build(); } @Override public Map getOptions(Set set) { - ImmutableMap.Builder options = ImmutableMap.builder(); - ContextSet contexts = LuckPermsService.convertContexts(set); - - int prefixPriority = Integer.MIN_VALUE; - int suffixPriority = Integer.MIN_VALUE; - - for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { - if (!n.getValue()) { - continue; - } - - if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) { - continue; - } - - if (!n.shouldApplyWithContext(contexts, true)) { - continue; - } - - if (n.isPrefix()) { - Map.Entry value = n.getPrefix(); - if (value.getKey() > prefixPriority) { - options.put("prefix", value.getValue()); - prefixPriority = value.getKey(); - } - continue; - } - - if (n.isSuffix()) { - Map.Entry value = n.getSuffix(); - if (value.getKey() > suffixPriority) { - options.put("suffix", value.getValue()); - suffixPriority = value.getKey(); - } - continue; - } - - if (n.isMeta()) { - Map.Entry meta = n.getMeta(); - options.put(meta.getKey(), meta.getValue()); - } - } - - return options.build(); + return getAllOptions().getOrDefault(set, ImmutableMap.of()); } @Override public boolean setOption(Set set, String key, String value) { - ContextSet context = LuckPermsService.convertContexts(set); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_OPTION)) { + ContextSet context = LuckPermsService.convertContexts(set); - key = escapeCharacters(key); - value = escapeCharacters(value); + key = escapeCharacters(key); + value = escapeCharacters(value); - try { - if (enduring) { - holder.setPermission(new me.lucko.luckperms.common.core.Node.Builder("meta." + key + "." + value) - .withExtraContext(context) - .build() - ); - } else { - holder.setTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("meta." + key + "." + value) - .withExtraContext(context) - .build() - ); - } - } catch (ObjectAlreadyHasException ignored) {} - objectSave(holder); - return true; + try { + if (enduring) { + holder.setPermission(new me.lucko.luckperms.common.core.Node.Builder("meta." + key + "." + value) + .withExtraContext(context) + .build() + ); + } else { + holder.setTransientPermission(new me.lucko.luckperms.common.core.Node.Builder("meta." + key + "." + value) + .withExtraContext(context) + .build() + ); + } + } catch (ObjectAlreadyHasException ignored) {} + objectSave(holder); + return true; + } } @Override public boolean clearOptions(Set set) { - ContextSet context = LuckPermsService.convertContexts(set); - - List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix()) - .filter(node -> node.shouldApplyWithContext(context)) - .collect(Collectors.toList()); - - toRemove.forEach(n -> { - try { - if (enduring) { - holder.unsetPermission(n); - } else { - holder.unsetTransientPermission(n); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_OPTIONS)) { + List toRemove = new ArrayList<>(); + for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { + if (!n.isMeta() && !n.isPrefix() && !n.isSuffix()) { + continue; } - } catch (ObjectLacksException ignored) {} - }); - objectSave(holder); - return !toRemove.isEmpty(); + Set contexts = LuckPermsService.convertContexts(n.getContexts()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (contexts.equals(set)) { + toRemove.add(n); + } + } + + toRemove.forEach(n -> { + try { + if (enduring) { + holder.unsetPermission(n); + } else { + holder.unsetTransientPermission(n); + } + } catch (ObjectLacksException ignored) {} + }); + + objectSave(holder); + return !toRemove.isEmpty(); + } } @Override public boolean clearOptions() { - List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() - .filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix()) - .collect(Collectors.toList()); + try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_OPTIONS)) { + List toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream() + .filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix()) + .collect(Collectors.toList()); - toRemove.forEach(n -> { - try { - if (enduring) { - holder.unsetPermission(n); - } else { - holder.unsetTransientPermission(n); - } - } catch (ObjectLacksException ignored) {} - }); + toRemove.forEach(n -> { + try { + if (enduring) { + holder.unsetPermission(n); + } else { + holder.unsetTransientPermission(n); + } + } catch (ObjectLacksException ignored) {} + }); - objectSave(holder); - return !toRemove.isEmpty(); + objectSave(holder); + return !toRemove.isEmpty(); + } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsUserSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsUserSubject.java index a4d9a80ad..6df07f0e2 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsUserSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsUserSubject.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service; +import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; import lombok.AccessLevel; import lombok.EqualsAndHashCode; @@ -29,6 +30,7 @@ import lombok.Getter; import me.lucko.luckperms.api.caching.MetaData; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; @@ -61,15 +63,6 @@ public class LuckPermsUserSubject extends LuckPermsSubject { this.transientSubjectData = new LuckPermsSubjectData(false, service, user); } - public void deprovision() { - /* For some reason, Sponge holds onto User instances in a cache, which in turn, prevents LuckPerms data from being GCed. - As well as unloading, we also remove all references to the User instances. */ - user = null; - service = null; - subjectData = null; - transientSubjectData = null; - } - private boolean hasData() { return user.getUserData() != null; } @@ -98,70 +91,82 @@ public class LuckPermsUserSubject extends LuckPermsSubject { @Override public Tristate getPermissionValue(ContextSet contexts, String permission) { - return !hasData() ? - Tristate.UNDEFINED : - LuckPermsService.convertTristate(user.getUserData().getPermissionData(service.calculateContexts(contexts)).getPermissionValue(permission)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_GET_PERMISSION_VALUE)) { + return !hasData() ? + Tristate.UNDEFINED : + LuckPermsService.convertTristate( + user.getUserData().getPermissionData(service.calculateContexts(contexts)).getPermissionValue(permission) + ); + } } @Override public boolean isChildOf(ContextSet contexts, Subject parent) { - return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_IS_CHILD_OF)) { + return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); + } } @Override public List getParents(ContextSet contexts) { - ImmutableList.Builder subjects = ImmutableList.builder(); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_GET_PARENTS)) { + ImmutableList.Builder subjects = ImmutableList.builder(); - if (hasData()) { - for (String perm : user.getUserData().getPermissionData(service.calculateContexts(contexts)).getImmutableBacking().keySet()) { - if (!perm.startsWith("group.")) { - continue; - } + if (hasData()) { + for (String perm : user.getUserData().getPermissionData(service.calculateContexts(contexts)).getImmutableBacking().keySet()) { + if (!perm.startsWith("group.")) { + continue; + } - String groupName = perm.substring("group.".length()); - if (service.getPlugin().getGroupManager().isLoaded(groupName)) { - subjects.add(service.getGroupSubjects().get(groupName)); + String groupName = perm.substring("group.".length()); + if (service.getPlugin().getGroupManager().isLoaded(groupName)) { + subjects.add(service.getGroupSubjects().get(groupName)); + } } } + + subjects.addAll(service.getUserSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts))); + subjects.addAll(service.getDefaults().getParents(LuckPermsService.convertContexts(contexts))); + + return subjects.build(); } - - subjects.addAll(service.getUserSubjects().getDefaults().getParents(LuckPermsService.convertContexts(contexts))); - subjects.addAll(service.getDefaults().getParents(LuckPermsService.convertContexts(contexts))); - - return subjects.build(); } @Override public Optional getOption(ContextSet contexts, String s) { - if (hasData()) { - MetaData data = user.getUserData().getMetaData(service.calculateContexts(contexts)); - if (s.equalsIgnoreCase("prefix")) { - if (data.getPrefix() != null) { - return Optional.of(data.getPrefix()); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_GET_OPTION)) { + if (hasData()) { + MetaData data = user.getUserData().getMetaData(service.calculateContexts(contexts)); + if (s.equalsIgnoreCase("prefix")) { + if (data.getPrefix() != null) { + return Optional.of(data.getPrefix()); + } + } + + if (s.equalsIgnoreCase("suffix")) { + if (data.getSuffix() != null) { + return Optional.of(data.getSuffix()); + } + } + + if (data.getMeta().containsKey(s)) { + return Optional.of(data.getMeta().get(s)); } } - if (s.equalsIgnoreCase("suffix")) { - if (data.getSuffix() != null) { - return Optional.of(data.getSuffix()); - } + Optional v = service.getUserSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); + if (v.isPresent()) { + return v; } - if (data.getMeta().containsKey(s)) { - return Optional.of(data.getMeta().get(s)); - } + return service.getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); } - - Optional v = service.getUserSubjects().getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); - if (v.isPresent()) { - return v; - } - - return service.getDefaults().getOption(LuckPermsService.convertContexts(contexts), s); } @Override public ContextSet getActiveContextSet() { - return service.getPlugin().getContextManager().getApplicableContext(this); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_GET_ACTIVE_CONTEXTS)) { + return service.getPlugin().getContextManager().getApplicableContext(this); + } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java index e9cae3c71..7fab4b87a 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service.collections; +import co.aikar.timings.Timing; import lombok.NonNull; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.groups.GroupManager; @@ -29,6 +30,7 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.sponge.service.LuckPermsGroupSubject; import me.lucko.luckperms.sponge.service.LuckPermsService; import me.lucko.luckperms.sponge.service.simple.SimpleCollection; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.Subject; @@ -58,11 +60,13 @@ public class GroupCollection implements SubjectCollection { @Override public Subject get(@NonNull String id) { - if (manager.isLoaded(id)) { - return LuckPermsGroupSubject.wrapGroup(manager.get(id), service); - } + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_COLLECTION_GET)) { + if (manager.isLoaded(id)) { + return LuckPermsGroupSubject.wrapGroup(manager.get(id), service); + } - return fallback.get(id); + return fallback.get(id); + } } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java index fdd7d2899..2b159a545 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java @@ -22,11 +22,13 @@ package me.lucko.luckperms.sponge.service.collections; +import co.aikar.timings.Timing; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.UncheckedExecutionException; import lombok.NonNull; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.commands.Util; @@ -36,6 +38,7 @@ import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.sponge.service.LuckPermsService; import me.lucko.luckperms.sponge.service.LuckPermsUserSubject; import me.lucko.luckperms.sponge.service.simple.SimpleCollection; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.Subject; @@ -71,7 +74,7 @@ public class UserCollection implements SubjectCollection { public LuckPermsUserSubject load(UUID uuid) throws Exception { User user = manager.get(uuid); if (user == null) { - throw new IllegalStateException("user not loaded"); + throw new IllegalStateException("User not loaded"); } return LuckPermsUserSubject.wrapUser(user, service); @@ -100,13 +103,15 @@ public class UserCollection implements SubjectCollection { @Override public Subject get(@NonNull String id) { - Optional s = getIfLoaded(id); - if (s.isPresent()) { - return s.get(); - } + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.USER_COLLECTION_GET)) { + Optional s = getIfLoaded(id); + if (s.isPresent()) { + return s.get(); + } - // Fallback to the other collection. This Subject instance will never be persisted. - return fallback.get(id); + // Fallback to the other collection. This Subject instance will never be persisted. + return fallback.get(id); + } } private Optional getIfLoaded(String id) { @@ -135,7 +140,7 @@ public class UserCollection implements SubjectCollection { UUID internal = service.getPlugin().getUuidCache().getUUID(uuid); try { return Optional.of(users.get(internal)); - } catch (ExecutionException e) { + } catch (ExecutionException | UncheckedExecutionException e) { return Optional.empty(); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java index a7499bda5..85381ad91 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java @@ -22,11 +22,13 @@ package me.lucko.luckperms.sponge.service.persisted; +import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.common.utils.BufferedRequest; import me.lucko.luckperms.sponge.service.LuckPermsService; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.MemorySubjectData; @@ -95,96 +97,106 @@ public class PersistedSubject implements Subject { @Override public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { - Tristate res = subjectData.getNodeTree(contexts).get(node); - if (res != Tristate.UNDEFINED) { - return res; - } - - res = transientSubjectData.getNodeTree(contexts).get(node); - if (res != Tristate.UNDEFINED) { - return res; - } - - for (Subject parent : getParents(contexts)) { - Tristate tempRes = parent.getPermissionValue(contexts, node); - if (tempRes != Tristate.UNDEFINED) { - return tempRes; + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_PERMISSION_VALUE)) { + Tristate res = subjectData.getNodeTree(contexts).get(node); + if (res != Tristate.UNDEFINED) { + return res; } - } - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return Tristate.UNDEFINED; - } + res = transientSubjectData.getNodeTree(contexts).get(node); + if (res != Tristate.UNDEFINED) { + return res; + } - res = service.getGroupSubjects().getDefaults().getPermissionValue(contexts, node); - if (res != Tristate.UNDEFINED) { + for (Subject parent : getParents(contexts)) { + Tristate tempRes = parent.getPermissionValue(contexts, node); + if (tempRes != Tristate.UNDEFINED) { + return tempRes; + } + } + + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return Tristate.UNDEFINED; + } + + res = service.getGroupSubjects().getDefaults().getPermissionValue(contexts, node); + if (res != Tristate.UNDEFINED) { + return res; + } + + res = service.getDefaults().getPermissionValue(contexts, node); return res; } - - res = service.getDefaults().getPermissionValue(contexts, node); - return res; } @Override public boolean isChildOf(@NonNull Set contexts, @NonNull Subject subject) { - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return subjectData.getParents(contexts).contains(subject) || - transientSubjectData.getParents(contexts).contains(subject); - } else { - return subjectData.getParents(contexts).contains(subject) || - transientSubjectData.getParents(contexts).contains(subject) || - getContainingCollection().getDefaults().getParents(contexts).contains(subject) || - service.getDefaults().getParents(contexts).contains(subject); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_IS_CHILD_OF)) { + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return subjectData.getParents(contexts).contains(subject) || + transientSubjectData.getParents(contexts).contains(subject); + } else { + return subjectData.getParents(contexts).contains(subject) || + transientSubjectData.getParents(contexts).contains(subject) || + getContainingCollection().getDefaults().getParents(contexts).contains(subject) || + service.getDefaults().getParents(contexts).contains(subject); + } } } @Override public List getParents(@NonNull Set contexts) { - List s = new ArrayList<>(); - s.addAll(subjectData.getParents(contexts)); - s.addAll(transientSubjectData.getParents(contexts)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_PARENTS)) { + List s = new ArrayList<>(); + s.addAll(subjectData.getParents(contexts)); + s.addAll(transientSubjectData.getParents(contexts)); - if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - s.addAll(getContainingCollection().getDefaults().getParents(contexts)); - s.addAll(service.getDefaults().getParents(contexts)); + if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + s.addAll(getContainingCollection().getDefaults().getParents(contexts)); + s.addAll(service.getDefaults().getParents(contexts)); + } + + return ImmutableList.copyOf(s); } - - return ImmutableList.copyOf(s); } @Override public Optional getOption(Set set, String key) { - Optional res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key)); - if (res.isPresent()) { - return res; - } - - res = Optional.ofNullable(transientSubjectData.getOptions(getActiveContexts()).get(key)); - if (res.isPresent()) { - return res; - } - - for (Subject parent : getParents(getActiveContexts())) { - Optional tempRes = parent.getOption(getActiveContexts(), key); - if (tempRes.isPresent()) { - return tempRes; + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_OPTION)) { + Optional res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key)); + if (res.isPresent()) { + return res; } - } - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return Optional.empty(); - } + res = Optional.ofNullable(transientSubjectData.getOptions(getActiveContexts()).get(key)); + if (res.isPresent()) { + return res; + } - res = getContainingCollection().getDefaults().getOption(set, key); - if (res.isPresent()) { - return res; - } + for (Subject parent : getParents(getActiveContexts())) { + Optional tempRes = parent.getOption(getActiveContexts(), key); + if (tempRes.isPresent()) { + return tempRes; + } + } - return service.getDefaults().getOption(set, key); + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return Optional.empty(); + } + + res = getContainingCollection().getDefaults().getOption(set, key); + if (res.isPresent()) { + return res; + } + + return service.getDefaults().getOption(set, key); + } } @Override public Set getActiveContexts() { - return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_ACTIVE_CONTEXTS)) { + return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java index 71a246f3b..43ba59521 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java @@ -22,10 +22,12 @@ package me.lucko.luckperms.sponge.service.simple; +import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.sponge.service.LuckPermsService; +import me.lucko.luckperms.sponge.timings.LPTiming; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.MemorySubjectData; @@ -74,83 +76,93 @@ public class SimpleSubject implements Subject { @Override public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { - Tristate res = subjectData.getNodeTree(contexts).get(node); - if (res != Tristate.UNDEFINED) { - return res; - } - - for (Subject parent : getParents(contexts)) { - Tristate tempRes = parent.getPermissionValue(contexts, node); - if (tempRes != Tristate.UNDEFINED) { - return tempRes; + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_PERMISSION_VALUE)) { + Tristate res = subjectData.getNodeTree(contexts).get(node); + if (res != Tristate.UNDEFINED) { + return res; } - } - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return Tristate.UNDEFINED; - } + for (Subject parent : getParents(contexts)) { + Tristate tempRes = parent.getPermissionValue(contexts, node); + if (tempRes != Tristate.UNDEFINED) { + return tempRes; + } + } - res = service.getGroupSubjects().getDefaults().getPermissionValue(contexts, node); - if (res != Tristate.UNDEFINED) { + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return Tristate.UNDEFINED; + } + + res = service.getGroupSubjects().getDefaults().getPermissionValue(contexts, node); + if (res != Tristate.UNDEFINED) { + return res; + } + + res = service.getDefaults().getPermissionValue(contexts, node); return res; } - - res = service.getDefaults().getPermissionValue(contexts, node); - return res; } @Override public boolean isChildOf(@NonNull Set contexts, @NonNull Subject subject) { - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return subjectData.getParents(contexts).contains(subject); - } else { - return subjectData.getParents(contexts).contains(subject) || - getContainingCollection().getDefaults().getParents(contexts).contains(subject) || - service.getDefaults().getParents(contexts).contains(subject); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_IS_CHILD_OF)) { + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return subjectData.getParents(contexts).contains(subject); + } else { + return subjectData.getParents(contexts).contains(subject) || + getContainingCollection().getDefaults().getParents(contexts).contains(subject) || + service.getDefaults().getParents(contexts).contains(subject); + } } } @Override public List getParents(@NonNull Set contexts) { - List s = new ArrayList<>(); - s.addAll(subjectData.getParents(contexts)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_PARENTS)) { + List s = new ArrayList<>(); + s.addAll(subjectData.getParents(contexts)); - if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")){ - s.addAll(getContainingCollection().getDefaults().getParents(contexts)); - s.addAll(service.getDefaults().getParents(contexts)); + if (!getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")){ + s.addAll(getContainingCollection().getDefaults().getParents(contexts)); + s.addAll(service.getDefaults().getParents(contexts)); + } + + return ImmutableList.copyOf(s); } - - return ImmutableList.copyOf(s); } @Override public Optional getOption(Set set, String key) { - Optional res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key)); - if (res.isPresent()) { - return res; - } - - for (Subject parent : getParents(getActiveContexts())) { - Optional tempRes = parent.getOption(getActiveContexts(), key); - if (tempRes.isPresent()) { - return tempRes; + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_OPTION)) { + Optional res = Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key)); + if (res.isPresent()) { + return res; } - } - if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { - return Optional.empty(); - } + for (Subject parent : getParents(getActiveContexts())) { + Optional tempRes = parent.getOption(getActiveContexts(), key); + if (tempRes.isPresent()) { + return tempRes; + } + } - res = getContainingCollection().getDefaults().getOption(set, key); - if (res.isPresent()) { - return res; - } + if (getContainingCollection().getIdentifier().equalsIgnoreCase("defaults")) { + return Optional.empty(); + } - return service.getDefaults().getOption(set, key); + res = getContainingCollection().getDefaults().getOption(set, key); + if (res.isPresent()) { + return res; + } + + return service.getDefaults().getOption(set, key); + } } @Override public Set getActiveContexts() { - return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_ACTIVE_CONTEXTS)) { + return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTiming.java b/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTiming.java new file mode 100644 index 000000000..9cbf3a6fd --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTiming.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.sponge.timings; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum LPTiming { + + GET_SUBJECTS("getSubjects"), + + USER_COLLECTION_GET("userCollectionGet"), + GROUP_COLLECTION_GET("groupCollectionGet"), + + USER_GET_PERMISSION_VALUE("userGetPermissionValue"), + USER_GET_PARENTS("userGetParents"), + USER_IS_CHILD_OF("userIsChildOf"), + USER_GET_OPTION("userGetOption"), + USER_GET_ACTIVE_CONTEXTS("userGetActiveContexts"), + + GROUP_GET_PERMISSION_VALUE("groupGetPermissionValue"), + GROUP_GET_PARENTS("groupGetParents"), + GROUP_IS_CHILD_OF("groupIsChildOf"), + GROUP_GET_OPTION("groupGetOption"), + GROUP_GET_ACTIVE_CONTEXTS("groupGetActiveContexts"), + + LP_SUBJECT_GET_PERMISSIONS("lpSubjectGetPermissions"), + LP_SUBJECT_SET_PERMISSION("lpSubjectSetPermission"), + LP_SUBJECT_CLEAR_PERMISSIONS("lpSubjectClearPermissions"), + LP_SUBJECT_GET_PARENTS("lpSubjectGetParents"), + LP_SUBJECT_ADD_PARENT("lpSubjectAddParent"), + LP_SUBJECT_REMOVE_PARENT("lpSubjectRemoveParent"), + LP_SUBJECT_CLEAR_PARENTS("lpSubjectClearParents"), + LP_SUBJECT_GET_OPTIONS("lpSubjectGetOptions"), + LP_SUBJECT_SET_OPTION("lpSubjectSetOption"), + LP_SUBJECT_CLEAR_OPTIONS("lpSubjectClearOptions"), + + SIMPLE_SUBJECT_GET_PERMISSION_VALUE("simpleSubjectGetPermissionValue"), + SIMPLE_SUBJECT_IS_CHILD_OF("simpleSubjectIsChildOf"), + SIMPLE_SUBJECT_GET_PARENTS("simpleSubjectGetParents"), + SIMPLE_SUBJECT_GET_OPTION("simpleSubjectGetOption"), + SIMPLE_SUBJECT_GET_ACTIVE_CONTEXTS("simpleSubjectGetActiveContexts"), + + PERSISTED_SUBJECT_GET_PERMISSION_VALUE("persistedSubjectGetPermissionValue"), + PERSISTED_SUBJECT_IS_CHILD_OF("persistedSubjectIsChildOf"), + PERSISTED_SUBJECT_GET_PARENTS("persistedSubjectGetParents"), + PERSISTED_SUBJECT_GET_OPTION("persistedSubjectGetOption"), + PERSISTED_SUBJECT_GET_ACTIVE_CONTEXTS("persistedSubjectGetActiveContexts"), + + ON_COMMAND("onCommand"), + COMMAND_TAB_COMPLETE("commandTabComplete"), + ON_CLIENT_LOGIN("onClientLogin"), + ON_CLIENT_LEAVE("onClientLeave"); + + private final String id; + +} diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTimings.java b/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTimings.java new file mode 100644 index 000000000..afb37768a --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/timings/LPTimings.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.sponge.timings; + +import co.aikar.timings.Timing; +import co.aikar.timings.Timings; +import com.google.common.collect.ImmutableMap; +import lombok.NonNull; +import me.lucko.luckperms.sponge.LPSpongePlugin; + +import java.util.Map; + +public class LPTimings { + private final Map timings; + + public LPTimings(LPSpongePlugin plugin) { + ImmutableMap.Builder map = ImmutableMap.builder(); + for (LPTiming t : LPTiming.values()) { + map.put(t, Timings.of(plugin, t.getId())); + } + + timings = map.build(); + } + + public Timing time(@NonNull LPTiming timing) { + Timing t = timings.get(timing); + t.startTimingIfSync(); + return t; + } +}