mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-30 22:53:27 +01:00
extract WeightCache out of PermissionHolder
This commit is contained in:
parent
7e7268bb5a
commit
63f8e8849f
@ -57,7 +57,11 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* A map of nodes held by a {@link PermissionHolder}.
|
||||
*
|
||||
* Each holder has two of these maps, one for enduring and transient nodes.
|
||||
* <p>Permissions are stored in Multimaps, with the context of the node being the key, and the actual Node object being
|
||||
* the value. The keys (context sets) are ordered according to their weight {@link ContextSetComparator}, and the values
|
||||
* are ordered according to the priority of the node, according to {@link NodeComparator}.</p>
|
||||
*
|
||||
* <p>Each holder has two of these maps, one for enduring and transient nodes.</p>
|
||||
*/
|
||||
public final class NodeMap {
|
||||
|
||||
|
@ -44,11 +44,9 @@ import me.lucko.luckperms.common.caching.HolderCachedData;
|
||||
import me.lucko.luckperms.common.caching.handlers.StateListener;
|
||||
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.contexts.ContextSetComparator;
|
||||
import me.lucko.luckperms.common.node.ImmutableLocalizedNode;
|
||||
import me.lucko.luckperms.common.node.InheritanceInfo;
|
||||
import me.lucko.luckperms.common.node.MetaType;
|
||||
import me.lucko.luckperms.common.node.NodeComparator;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
import me.lucko.luckperms.common.node.NodeTools;
|
||||
import me.lucko.luckperms.common.node.NodeWithContextComparator;
|
||||
@ -79,63 +77,74 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* Represents an object that can hold permissions, (a user or group)
|
||||
*
|
||||
* <p>Permissions are stored in Multimaps, with the context of the node being the key, and the actual Node object being
|
||||
* the value. The keys (context sets) are ordered according to their weight {@link ContextSetComparator}, and the values
|
||||
* are ordered according to the priority of the node, according to {@link NodeComparator}.</p>
|
||||
* <p>Data is stored in {@link NodeMap}s. A holder has two of these, one for
|
||||
* enduring nodes and one for transient nodes.</p>
|
||||
*
|
||||
* <p>This class also provides a number of methods to perform inheritance lookups. These lookup methods initially use
|
||||
* Lists of nodes populated with the inheritance tree. Nodes at the start of this list have priority over nodes at the
|
||||
* end. Nodes higher up the tree appear at the end of these lists. In order to remove duplicate elements, the lists are
|
||||
* flattened using the methods in {@link NodeTools}. This is significantly faster than trying to prevent duplicates
|
||||
* throughout the process of accumulation, and reduces the need for too much caching.</p>
|
||||
* <p>This class provides a number of methods to perform inheritance lookups.
|
||||
* These lookup methods initially use Lists of nodes populated with the
|
||||
* inheritance tree. Nodes at the start of this list have priority over nodes at
|
||||
* the end. Nodes higher up the tree appear at the end of these lists. In order
|
||||
* to remove duplicate elements, the lists are flattened using the methods in
|
||||
* {@link NodeTools}. This is significantly faster than trying to prevent
|
||||
* duplicates throughout the process of accumulation, and reduces the need for
|
||||
* too much caching.</p>
|
||||
*
|
||||
* <p>Cached state is avoided in these instances to cut down on memory footprint. The nodes are stored indexed to the
|
||||
* contexts they apply in, so doing context specific querying should be fast. Caching would be ineffective here, due to
|
||||
* the potentially vast amount of contexts being used by nodes, and the potential for very large inheritance trees.</p>
|
||||
* <p>Cached state is avoided in these instances to cut down on memory
|
||||
* footprint. The nodes are stored indexed to the contexts they apply in, so
|
||||
* doing context specific querying should be fast. Caching would be ineffective
|
||||
* here, due to the potentially vast amount of contexts being used by nodes,
|
||||
* and the potential for very large inheritance trees.</p>
|
||||
*/
|
||||
public abstract class PermissionHolder {
|
||||
|
||||
/**
|
||||
* The name of this PermissionHolder object.
|
||||
* The name of this object.
|
||||
*
|
||||
* <p>Used to prevent circular inheritance issues.</p>
|
||||
* <p>Used as a base for identifying permission holding objects. Also acts
|
||||
* as a method for preventing circular inheritance issues.</p>
|
||||
*
|
||||
* <p>For users, this value is a String representation of their {@link User#getUuid()}. For groups, it's just the
|
||||
* {@link Group#getName()}.</p>
|
||||
* @see User#getUuid()
|
||||
* @see Group#getName()
|
||||
* @see #getObjectName()
|
||||
*/
|
||||
private final String objectName;
|
||||
|
||||
/**
|
||||
* Reference to the main plugin instance
|
||||
* @see #getPlugin()
|
||||
*/
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
/**
|
||||
* The holders persistent nodes.
|
||||
*
|
||||
* <p>These (unlike transient nodes) are saved to the storage backing.</p>
|
||||
*
|
||||
* @see #getEnduringData()
|
||||
*/
|
||||
private final NodeMap enduringNodes = new NodeMap(this);
|
||||
|
||||
/**
|
||||
* The holders transient 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>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>
|
||||
*
|
||||
* @see #getTransientData()
|
||||
*/
|
||||
private final NodeMap transientNodes = new NodeMap(this);
|
||||
|
||||
/**
|
||||
* Caches the holders weight lookup
|
||||
* Caches the holders weight
|
||||
* @see #getWeight()
|
||||
*/
|
||||
private final Cache<OptionalInt> weightCache = new Cache<OptionalInt>() {
|
||||
@Override
|
||||
protected OptionalInt supply() {
|
||||
return calculateWeight();
|
||||
}
|
||||
};
|
||||
private final Cache<OptionalInt> weightCache = WeightCache.getFor(this);
|
||||
|
||||
/**
|
||||
* Lock used by Storage implementations to prevent concurrent read/writes
|
||||
* @see #getIoLock()
|
||||
*/
|
||||
private final Lock ioLock = new ReentrantLock();
|
||||
|
||||
@ -1003,34 +1012,6 @@ public abstract class PermissionHolder {
|
||||
return this.weightCache.get();
|
||||
}
|
||||
|
||||
private OptionalInt calculateWeight() {
|
||||
if (this.getType().isUser()) return OptionalInt.empty();
|
||||
|
||||
boolean seen = false;
|
||||
int best = 0;
|
||||
for (Node n : getOwnNodes(ImmutableContextSet.empty())) {
|
||||
Integer weight = NodeFactory.parseWeightNode(n.getPermission());
|
||||
if (weight == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seen || weight > best) {
|
||||
seen = true;
|
||||
best = weight;
|
||||
}
|
||||
}
|
||||
OptionalInt weight = seen ? OptionalInt.of(best) : OptionalInt.empty();
|
||||
|
||||
if (!weight.isPresent()) {
|
||||
Integer w = this.plugin.getConfiguration().get(ConfigKeys.GROUP_WEIGHTS).get(getObjectName().toLowerCase());
|
||||
if (w != null) {
|
||||
weight = OptionalInt.of(w);
|
||||
}
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
public Set<HolderReference> getGroupReferences() {
|
||||
return getOwnNodes().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.model;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.common.buffers.Cache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* Cache instance to supply the weight of a {@link PermissionHolder}.
|
||||
*/
|
||||
public class WeightCache extends Cache<OptionalInt> {
|
||||
private static final Cache<OptionalInt> NULL = new Cache<OptionalInt>() {
|
||||
@Override
|
||||
protected OptionalInt supply() {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
};
|
||||
|
||||
public static Cache<OptionalInt> getFor(PermissionHolder holder) {
|
||||
if (holder.getType().isUser()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new WeightCache(((Group) holder));
|
||||
}
|
||||
|
||||
private final Group group;
|
||||
|
||||
private WeightCache(Group group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OptionalInt supply() {
|
||||
boolean seen = false;
|
||||
int best = 0;
|
||||
for (Node n : this.group.getOwnNodes(ImmutableContextSet.empty())) {
|
||||
Integer weight = NodeFactory.parseWeightNode(n.getPermission());
|
||||
if (weight == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seen || weight > best) {
|
||||
seen = true;
|
||||
best = weight;
|
||||
}
|
||||
}
|
||||
OptionalInt weight = seen ? OptionalInt.of(best) : OptionalInt.empty();
|
||||
|
||||
if (!weight.isPresent()) {
|
||||
Map<String, Integer> configWeights = this.group.getPlugin().getConfiguration().get(ConfigKeys.GROUP_WEIGHTS);
|
||||
Integer w = configWeights.get(this.group.getObjectName().toLowerCase());
|
||||
if (w != null) {
|
||||
weight = OptionalInt.of(w);
|
||||
}
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user