Improve performance of resolve methods in PermissionHolder, other cleanup

This commit is contained in:
Luck 2017-04-04 15:22:25 +01:00
parent 055dfb000d
commit e68fc7c558
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
19 changed files with 120 additions and 75 deletions

View File

@ -114,6 +114,20 @@ public interface Node extends Map.Entry<String, Boolean> {
*/
boolean hasSpecificContext();
/**
* Returns if this node is able to apply in the given context
*
* @param includeGlobal if global server values should apply
* @param includeGlobalWorld if global world values should apply
* @param server the server being checked against, or null
* @param world the world being checked against, or null
* @param context the context being checked against, or null
* @param applyRegex if regex should be applied
* @return true if the node should apply, otherwise false
* @since 3.1
*/
boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, String server, String world, ContextSet context, boolean applyRegex);
/**
* If this node should apply on a specific server
*

View File

@ -74,7 +74,7 @@ public class Injector {
existing.clearPermissions();
lpPermissible.getActive().set(true);
lpPermissible.recalculatePermissions();
lpPermissible.recalculatePermissions(false);
lpPermissible.setOldPermissible(existing);
lpPermissible.updateSubscriptionsAsync();

View File

@ -271,6 +271,10 @@ public class LPPermissible extends PermissibleBase {
@Override
public void recalculatePermissions() {
recalculatePermissions(true);
}
public void recalculatePermissions(boolean invalidate) {
if (attachmentPermissions == null) {
return;
}
@ -281,7 +285,7 @@ public class LPPermissible extends PermissibleBase {
calculateChildPermissions(attachment.getPermissions(), false, attachment);
}
if (hasData()) {
if (hasData() && invalidate) {
user.getUserData().invalidatePermissionCalculators();
}
}

View File

@ -38,7 +38,7 @@ import java.util.function.Consumer;
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class UserReference implements HolderReference<UserIdentifier> {
public final class UserReference implements HolderReference<UserIdentifier> {
private final UserIdentifier id;
@Override

View File

@ -41,7 +41,7 @@ import java.util.UUID;
*/
@Getter
@EqualsAndHashCode(of = "uuid")
public class AbstractSender<T> implements Sender {
public final class AbstractSender<T> implements Sender {
private final LuckPermsPlugin platform;
private final SenderFactory<T> factory;
private final WeakReference<T> ref;

View File

@ -171,6 +171,14 @@ public class ArgumentUtils {
set.add(key, value);
}
// remove any potential "global" context mappings
set.remove("server", "global");
set.remove("world", "global");
set.remove("server", "null");
set.remove("world", "null");
set.remove("server", "*");
set.remove("world", "*");
// remove excess entries from the set.
// (it can only have one server and one world.)
List<String> servers = new ArrayList<>(set.getValues("server"));

View File

@ -40,7 +40,7 @@ import java.util.Optional;
@ToString
@EqualsAndHashCode
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class InheritanceInfo {
public final class InheritanceInfo {
public static InheritanceInfo of(@NonNull LocalizedNode node) {
return new InheritanceInfo(node.getTristate(), node.getLocation());
}

View File

@ -36,7 +36,7 @@ import java.util.UUID;
@ToString
@EqualsAndHashCode(of = "uuid")
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class UserIdentifier implements Identifiable<UUID> {
public final class UserIdentifier implements Identifiable<UUID> {
public static UserIdentifier of(UUID uuid, String username) {
return new UserIdentifier(uuid, username);
}

View File

@ -57,7 +57,7 @@ import java.util.stream.Collectors;
@SuppressWarnings("OptionalGetWithoutIsPresent")
@ToString(of = {"permission", "value", "override", "server", "world", "expireAt", "contexts"})
@EqualsAndHashCode(of = {"permission", "value", "override", "server", "world", "expireAt", "contexts"})
public class ImmutableNode implements Node {
public final class ImmutableNode implements Node {
private static boolean shouldApply(String str, boolean applyRegex, String thisStr) {
if (str.equalsIgnoreCase(thisStr)) {
@ -389,6 +389,11 @@ public class ImmutableNode implements Node {
return suffix;
}
@Override
public boolean shouldApply(boolean includeGlobal, boolean includeGlobalWorld, String server, String world, ContextSet context, boolean applyRegex) {
return shouldApplyOnServer(server, includeGlobal, applyRegex) && shouldApplyOnWorld(world, includeGlobalWorld, applyRegex) && shouldApplyWithContext(context, false);
}
@Override
public boolean shouldApplyOnServer(String server, boolean includeGlobal, boolean applyRegex) {
if (server == null || server.equals("") || server.equalsIgnoreCase("global")) {

View File

@ -117,10 +117,6 @@ public abstract class PermissionHolder {
/**
* The holders persistent nodes.
*
* <p>These are nodes which are never stored or persisted to a file, and only
* last until the end of the objects lifetime. (for a group, that's when the server stops, and for a user, it's when
* they log out, or get unloaded.)</p>
*
* <p>Nodes are mapped by the result of {@link Node#getFullContexts()}, and keys are sorted by the weight of the
* ContextSet. ContextSets are ordered first by the presence of a server key, then by the presence of a world
* key, and finally by the overall size of the set. Nodes are ordered according to the priority rules
@ -345,6 +341,25 @@ public abstract class PermissionHolder {
}
}
public LinkedHashSet<Node> flattenAndMergeNodes(ContextSet filter) {
LinkedHashSet<Node> set = new LinkedHashSet<>();
synchronized (transientNodes) {
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : transientNodes.asMap().entrySet()) {
if (e.getKey().isSatisfiedBy(filter)) {
set.addAll(e.getValue());
}
}
}
synchronized (nodes) {
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : nodes.asMap().entrySet()) {
if (e.getKey().isSatisfiedBy(filter)) {
set.addAll(e.getValue());
}
}
}
return set;
}
public List<Node> flattenNodesToList() {
synchronized (nodes) {
return new ArrayList<>(nodes.values());
@ -387,6 +402,25 @@ public abstract class PermissionHolder {
}
}
public List<Node> flattenAndMergeNodesToList(ContextSet filter) {
List<Node> set = new ArrayList<>();
synchronized (transientNodes) {
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : transientNodes.asMap().entrySet()) {
if (e.getKey().isSatisfiedBy(filter)) {
set.addAll(e.getValue());
}
}
}
synchronized (nodes) {
for (Map.Entry<ImmutableContextSet, Collection<Node>> e : nodes.asMap().entrySet()) {
if (e.getKey().isSatisfiedBy(filter)) {
set.addAll(e.getValue());
}
}
}
return set;
}
public boolean removeIf(Predicate<Node> predicate) {
boolean result;
ImmutableSet<Node> before = ImmutableSet.copyOf(flattenNodes());
@ -439,28 +473,26 @@ public abstract class PermissionHolder {
excludedGroups.add(getObjectName().toLowerCase());
}
// get the objects own nodes
flattenTransientNodesToList(context.getContextSet()).stream()
.map(n -> ImmutableLocalizedNode.of(n, getObjectName()))
.forEach(accumulator::add);
flattenNodesToList(context.getContextSet()).stream()
// get and add the objects own nodes
List<Node> nodes = flattenAndMergeNodesToList(context.getContextSet());
nodes.stream()
.map(n -> ImmutableLocalizedNode.of(n, getObjectName()))
.forEach(accumulator::add);
Contexts contexts = context.getContexts();
String server = context.getServer();
String world = context.getWorld();
// screw effectively final
Set<String> finalExcludedGroups = excludedGroups;
List<LocalizedNode> finalAccumulator = accumulator;
mergePermissions().stream()
// this allows you to negate parent permissions lower down the inheritance tree.
// there's no way to distinct the stream below based on a custom comparator.
NodeTools.removeIgnoreValue(nodes.iterator());
nodes.stream()
.filter(Node::getValue)
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, contexts.isApplyGlobalGroups(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)))
.filter(n -> n.shouldApplyOnWorld(world, contexts.isApplyGlobalWorldGroups(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)))
.filter(n -> n.shouldApplyWithContext(contexts.getContexts(), false))
.filter(n -> !(!contexts.isApplyGlobalGroups() && !n.isServerSpecific()) && !(!contexts.isApplyGlobalWorldGroups() && !n.isWorldSpecific()))
.map(Node::getGroupName)
.distinct()
.map(n -> Optional.ofNullable(plugin.getGroupManager().getIfLoaded(n)))
@ -498,8 +530,6 @@ public abstract class PermissionHolder {
public SortedSet<LocalizedNode> getAllNodes(ExtractedContexts context) {
Contexts contexts = context.getContexts();
String server = context.getServer();
String world = context.getWorld();
List<LocalizedNode> entries;
if (contexts.isApplyGroups()) {
@ -508,13 +538,12 @@ public abstract class PermissionHolder {
entries = flattenNodesToList(context.getContextSet()).stream().map(n -> ImmutableLocalizedNode.of(n, getObjectName())).collect(Collectors.toList());
}
entries.removeIf(node ->
!node.isGroupNode() && (
!node.shouldApplyOnServer(server, contexts.isIncludeGlobal(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ||
!node.shouldApplyOnWorld(world, contexts.isIncludeGlobalWorld(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ||
!node.shouldApplyWithContext(context.getContextSet(), false)
)
);
if (!contexts.isIncludeGlobal()) {
entries.removeIf(n -> !n.isGroupNode() && !n.isServerSpecific());
}
if (!contexts.isApplyGlobalWorldGroups()) {
entries.removeIf(n -> !n.isGroupNode() && !n.isWorldSpecific());
}
NodeTools.removeSamePermission(entries.iterator());
SortedSet<LocalizedNode> ret = new TreeSet<>(PriorityComparator.reverse());
@ -524,8 +553,6 @@ public abstract class PermissionHolder {
public Map<String, Boolean> exportNodes(ExtractedContexts context, boolean lowerCase) {
Contexts contexts = context.getContexts();
String server = context.getServer();
String world = context.getWorld();
List<? extends Node> entries;
if (contexts.isApplyGroups()) {
@ -534,27 +561,22 @@ public abstract class PermissionHolder {
entries = flattenNodesToList(context.getContextSet());
}
entries.removeIf(node ->
!node.isGroupNode() && (
!node.shouldApplyOnServer(server, contexts.isIncludeGlobal(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ||
!node.shouldApplyOnWorld(world, contexts.isIncludeGlobalWorld(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ||
!node.shouldApplyWithContext(context.getContextSet(), false)
)
);
if (!contexts.isIncludeGlobal()) {
entries.removeIf(n -> !n.isGroupNode() && !n.isServerSpecific());
}
if (!contexts.isApplyGlobalWorldGroups()) {
entries.removeIf(n -> !n.isGroupNode() && !n.isWorldSpecific());
}
Map<String, Boolean> perms = new HashMap<>();
for (Node node : entries) {
String perm = lowerCase ? node.getPermission().toLowerCase() : node.getPermission();
if (!perms.containsKey(perm)) {
perms.put(perm, node.getValue());
if (perms.putIfAbsent(perm, node.getValue()) == null) {
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_SHORTHAND)) {
List<String> sh = node.resolveShorthand();
if (!sh.isEmpty()) {
sh.stream().map(s -> lowerCase ? s.toLowerCase() : s)
.filter(s -> !perms.containsKey(s))
.forEach(s -> perms.put(s, node.getValue()));
sh.stream().map(s -> lowerCase ? s.toLowerCase() : s).forEach(s -> perms.putIfAbsent(s, node.getValue()));
}
}
}
@ -580,27 +602,17 @@ public abstract class PermissionHolder {
}
Contexts contexts = context.getContexts();
String server = context.getServer();
String world = context.getWorld();
// screw effectively final
Set<String> finalExcludedGroups = excludedGroups;
MetaAccumulator finalAccumulator = accumulator;
flattenTransientNodesToList(context.getContextSet()).stream()
// get and add the objects own nodes
List<Node> nodes = flattenAndMergeNodesToList(context.getContextSet());
nodes.stream()
.filter(Node::getValue)
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
.filter(n -> n.shouldApplyOnServer(server, contexts.isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(world, contexts.isIncludeGlobalWorld(), false))
.filter(n -> n.shouldApplyWithContext(context.getContextSet(), false))
.forEach(n -> finalAccumulator.accumulateNode(ImmutableLocalizedNode.of(n, getObjectName())));
flattenNodesToList(context.getContextSet()).stream()
.filter(Node::getValue)
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
.filter(n -> n.shouldApplyOnServer(server, contexts.isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(world, contexts.isIncludeGlobalWorld(), false))
.filter(n -> n.shouldApplyWithContext(context.getContextSet(), false))
.filter(n -> !(!contexts.isIncludeGlobal() && !n.isServerSpecific()) && !(!contexts.isIncludeGlobalWorld() && !n.isWorldSpecific()))
.forEach(n -> finalAccumulator.accumulateNode(ImmutableLocalizedNode.of(n, getObjectName())));
OptionalInt w = getWeight();
@ -608,12 +620,14 @@ public abstract class PermissionHolder {
accumulator.accumulateWeight(w.getAsInt());
}
mergePermissions().stream()
// this allows you to negate parent permissions lower down the inheritance tree.
// there's no way to distinct the stream below based on a custom comparator.
NodeTools.removeIgnoreValue(nodes.iterator());
nodes.stream()
.filter(Node::getValue)
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, contexts.isApplyGlobalGroups(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)))
.filter(n -> n.shouldApplyOnWorld(world, contexts.isApplyGlobalWorldGroups(), plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)))
.filter(n -> n.shouldApplyWithContext(contexts.getContexts(), false))
.filter(n -> !(!contexts.isApplyGlobalGroups() && !n.isServerSpecific()) && !(!contexts.isApplyGlobalWorldGroups() && !n.isWorldSpecific()))
.map(Node::getGroupName)
.distinct()
.map(n -> Optional.ofNullable(plugin.getGroupManager().getIfLoaded(n)))

View File

@ -47,7 +47,7 @@ import java.util.Map;
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class NodeDataHolder {
public final class NodeDataHolder {
private static final Gson GSON = new Gson();
public static NodeDataHolder fromNode(Node node) {

View File

@ -38,7 +38,7 @@ import java.util.OptionalLong;
@Getter
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class NodeHeldPermission<T> implements HeldPermission<T> {
public final class NodeHeldPermission<T> implements HeldPermission<T> {
public static <T> NodeHeldPermission<T> of(T holder, NodeDataHolder nodeDataHolder) {
return of(holder, nodeDataHolder.toNode());
}

View File

@ -111,7 +111,7 @@ public abstract class Buffer<T, R> implements Runnable {
@Getter
@EqualsAndHashCode(of = "object")
@AllArgsConstructor
private static class BufferedObject<T, R> {
private static final class BufferedObject<T, R> {
@Setter
private long bufferTime;

View File

@ -38,7 +38,7 @@ import me.lucko.luckperms.api.Node;
@Getter
@ToString
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ImmutableLocalizedNode implements LocalizedNode {
public final class ImmutableLocalizedNode implements LocalizedNode {
public static ImmutableLocalizedNode of(@NonNull Node node, @NonNull String location) {
return new ImmutableLocalizedNode(node, location);
}

View File

@ -311,7 +311,7 @@ public class LuckPermsService implements PermissionService {
@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
public static class DescriptionBuilder implements PermissionDescription.Builder {
public static final class DescriptionBuilder implements PermissionDescription.Builder {
private final LuckPermsService service;
private final PluginContainer container;
private final Map<String, Tristate> roles = new HashMap<>();
@ -365,7 +365,7 @@ public class LuckPermsService implements PermissionService {
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public static class Description implements PermissionDescription {
public static final class Description implements PermissionDescription {
private final LuckPermsService service;
private final PluginContainer owner;
private final String id;

View File

@ -33,7 +33,7 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class OptionLookup {
public final class OptionLookup {
private final String key;
private final ImmutableContextSet contexts;

View File

@ -33,7 +33,7 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class PermissionLookup {
public final class PermissionLookup {
private final String node;
private final ImmutableContextSet contexts;

View File

@ -35,7 +35,7 @@ import java.lang.ref.WeakReference;
@ToString(of = "collection")
@EqualsAndHashCode(of = "collection")
@RequiredArgsConstructor(staticName = "of")
public class SubjectCollectionReference {
public final class SubjectCollectionReference {
@Getter
private final String collection;

View File

@ -40,7 +40,7 @@ import java.util.List;
@ToString(of = {"collection", "identifier"})
@EqualsAndHashCode(of = {"collection", "identifier"})
@RequiredArgsConstructor(staticName = "of")
public class SubjectReference {
public final class SubjectReference {
public static SubjectReference deserialize(String s) {
List<String> parts = Splitter.on('/').limit(2).splitToList(s);
return of(parts.get(0), parts.get(1));