Store all accumulated meta values in MetaCache

This commit is contained in:
Luck 2017-06-19 21:39:46 +01:00
parent 8766e3b408
commit e50fa17f7c
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
4 changed files with 55 additions and 20 deletions

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.api.caching; package me.lucko.luckperms.api.caching;
import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import java.util.Map; import java.util.Map;
@ -38,7 +40,24 @@ import java.util.SortedMap;
public interface MetaData { public interface MetaData {
/** /**
* Gets an immutable copy of the meta this user has * Gets an immutable copy of the meta this user has.
*
* <p>A list multimap is used because when inherited values are included, each key can be
* mapped to multiple values.</p>
*
* <p>The first value to be accumulated (and used to represent the key in {@link #getMeta()} is at index 0
* in the list. Any additional values are stored in order of accumulation.</p>
*
* @return an immutable multimap of meta
* @since 3.3
*/
ListMultimap<String, String> getMetaMultimap();
/**
* Gets an immutable copy of the meta this user has.
*
* <p>This map is formed by taking the entries in {@link #getMetaMultimap()}, and mapping each key
* to the value at index 0 in the corresponding list.</p>
* *
* @return an immutable map of meta * @return an immutable map of meta
*/ */

View File

@ -30,6 +30,9 @@ import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.ToString; import lombok.ToString;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
@ -38,7 +41,6 @@ import me.lucko.luckperms.common.metastacking.MetaStack;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
@ -57,7 +59,7 @@ public class MetaAccumulator {
} }
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private final Map<String, String> meta; private final ListMultimap<String, String> meta;
private final SortedMap<Integer, String> prefixes; private final SortedMap<Integer, String> prefixes;
private final SortedMap<Integer, String> suffixes; private final SortedMap<Integer, String> suffixes;
private int weight = 0; private int weight = 0;
@ -66,7 +68,7 @@ public class MetaAccumulator {
private final MetaStack suffixStack; private final MetaStack suffixStack;
public MetaAccumulator(@NonNull MetaStack prefixStack, @NonNull MetaStack suffixStack) { public MetaAccumulator(@NonNull MetaStack prefixStack, @NonNull MetaStack suffixStack) {
this.meta = new HashMap<>(); this.meta = ArrayListMultimap.create();
this.prefixes = new TreeMap<>(Comparator.reverseOrder()); this.prefixes = new TreeMap<>(Comparator.reverseOrder());
this.suffixes = new TreeMap<>(Comparator.reverseOrder()); this.suffixes = new TreeMap<>(Comparator.reverseOrder());
this.prefixStack = prefixStack; this.prefixStack = prefixStack;
@ -76,9 +78,7 @@ public class MetaAccumulator {
public void accumulateNode(LocalizedNode n) { public void accumulateNode(LocalizedNode n) {
if (n.isMeta()) { if (n.isMeta()) {
Map.Entry<String, String> entry = n.getMeta(); Map.Entry<String, String> entry = n.getMeta();
if (!meta.containsKey(entry.getKey())) { meta.put(entry.getKey(), entry.getValue());
meta.put(entry.getKey(), entry.getValue());
}
} }
if (n.isPrefix()) { if (n.isPrefix()) {
@ -106,7 +106,7 @@ public class MetaAccumulator {
// We can assume that if this method is being called, this holder is effectively finalized. (it's not going to accumulate more nodes) // We can assume that if this method is being called, this holder is effectively finalized. (it's not going to accumulate more nodes)
// Therefore, it should be ok to set the weight meta key, if not already present. // Therefore, it should be ok to set the weight meta key, if not already present.
public Map<String, String> getMeta() { public ListMultimap<String, String> getMeta() {
if (!this.meta.containsKey("weight") && this.weight != 0) { if (!this.meta.containsKey("weight") && this.weight != 0) {
this.meta.put("weight", String.valueOf(this.weight)); this.meta.put("weight", String.valueOf(this.weight));
} }

View File

@ -25,16 +25,20 @@
package me.lucko.luckperms.common.caching; package me.lucko.luckperms.common.caching;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.caching.MetaData; import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.common.metastacking.MetaStack; import me.lucko.luckperms.common.metastacking.MetaStack;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
@ -43,29 +47,38 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
/** /**
* Holds a user's cached meta for a given context * Holds a user's cached meta for a given context
*/ */
@Getter
@NoArgsConstructor @NoArgsConstructor
public class MetaCache implements MetaData { public class MetaCache implements MetaData {
@Getter(AccessLevel.NONE)
private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final ReadWriteLock lock = new ReentrantReadWriteLock();
@Getter private ListMultimap<String, String> metaMultimap = ImmutableListMultimap.of();
private Map<String, String> meta = ImmutableMap.of(); private Map<String, String> meta = ImmutableMap.of();
@Getter
private SortedMap<Integer, String> prefixes = ImmutableSortedMap.of(); private SortedMap<Integer, String> prefixes = ImmutableSortedMap.of();
@Getter
private SortedMap<Integer, String> suffixes = ImmutableSortedMap.of(); private SortedMap<Integer, String> suffixes = ImmutableSortedMap.of();
@Getter
private MetaStack prefixStack = null; private MetaStack prefixStack = null;
@Getter
private MetaStack suffixStack = null; private MetaStack suffixStack = null;
public void loadMeta(MetaAccumulator meta) { public void loadMeta(MetaAccumulator meta) {
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
this.meta = ImmutableMap.copyOf(meta.getMeta()); this.metaMultimap = ImmutableListMultimap.copyOf(meta.getMeta());
//noinspection unchecked
Map<String, List<String>> metaMap = (Map) this.metaMultimap.asMap();
ImmutableMap.Builder<String, String> metaMapBuilder = ImmutableMap.builder();
for (Map.Entry<String, List<String>> e : metaMap.entrySet()) {
if (e.getValue().isEmpty()) {
continue;
}
// take the value which was accumulated first
metaMapBuilder.put(e.getKey(), e.getValue().get(0));
}
this.meta = metaMapBuilder.build();
this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes()); this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes());
this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes()); this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes());
this.prefixStack = meta.getPrefixStack(); this.prefixStack = meta.getPrefixStack();

View File

@ -30,6 +30,7 @@ import lombok.Getter;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
@ -54,6 +55,7 @@ import org.spongepowered.api.service.permission.PermissionService;
import co.aikar.timings.Timing; import co.aikar.timings.Timing;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -238,8 +240,9 @@ public class SpongeGroup extends Group {
private Optional<String> getMeta(ImmutableContextSet contexts, String key) { private Optional<String> getMeta(ImmutableContextSet contexts, String key) {
MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, ExtractedContexts.generate(plugin.getService().calculateContexts(contexts))); MetaAccumulator metaAccumulator = parent.accumulateMeta(null, null, ExtractedContexts.generate(plugin.getService().calculateContexts(contexts)));
Map<String, String> meta = metaAccumulator.getMeta(); ListMultimap<String, String> meta = metaAccumulator.getMeta();
return Optional.ofNullable(meta.get(key)); List<String> ret = meta.get(key);
return ret.isEmpty() ? Optional.empty() : Optional.of(ret.get(0));
} }
} }
} }