Replace guava caches with caffeine

This commit is contained in:
Luck
2017-04-03 00:53:04 +01:00
Unverified
parent e7e2e3f7e0
commit 2749563f5d
23 changed files with 228 additions and 394 deletions
@@ -25,12 +25,10 @@ package me.lucko.luckperms.common.caching;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.caching.MetaData;
@@ -49,6 +47,7 @@ import java.util.concurrent.TimeUnit;
@RequiredArgsConstructor
public class UserCache implements UserData {
/**
* The user whom this data instance is representing
*/
@@ -59,7 +58,7 @@ public class UserCache implements UserData {
*/
private final CalculatorFactory calculatorFactory;
private final LoadingCache<Contexts, PermissionCache> permission = CacheBuilder.newBuilder()
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(new CacheLoader<Contexts, PermissionCache>() {
@Override
@@ -68,13 +67,13 @@ public class UserCache implements UserData {
}
@Override
public ListenableFuture<PermissionCache> reload(Contexts contexts, PermissionCache oldData) {
public PermissionCache reload(Contexts contexts, PermissionCache oldData) {
oldData.comparePermissions(user.exportNodes(ExtractedContexts.generate(contexts), true));
return Futures.immediateFuture(oldData);
return oldData;
}
});
private final LoadingCache<Contexts, MetaCache> meta = CacheBuilder.newBuilder()
private final LoadingCache<Contexts, MetaCache> meta = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(new CacheLoader<Contexts, MetaCache>() {
@Override
@@ -83,20 +82,20 @@ public class UserCache implements UserData {
}
@Override
public ListenableFuture<MetaCache> reload(Contexts contexts, MetaCache oldData) {
public MetaCache reload(Contexts contexts, MetaCache oldData) {
oldData.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
return Futures.immediateFuture(oldData);
return oldData;
}
});
@Override
public PermissionData getPermissionData(@NonNull Contexts contexts) {
return permission.getUnchecked(contexts);
return permission.get(contexts);
}
@Override
public MetaData getMetaData(@NonNull Contexts contexts) {
return meta.getUnchecked(contexts);
return meta.get(contexts);
}
@Override
@@ -142,8 +141,8 @@ public class UserCache implements UserData {
@Override
public void preCalculate(@NonNull Contexts contexts) {
permission.getUnchecked(contexts);
meta.getUnchecked(contexts);
permission.get(contexts);
meta.get(contexts);
}
public void invalidateCache() {
@@ -1,41 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.caching.holder;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.Contexts;
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class ExportNodesHolder {
private final Contexts contexts;
private final Boolean lowerCase;
}
@@ -1,43 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.caching.holder;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.common.utils.ExtractedContexts;
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(staticName = "of")
public class GetAllNodesRequest {
private final ImmutableSet<String> excludedGroups;
private final ExtractedContexts contexts;
}
@@ -24,9 +24,8 @@ package me.lucko.luckperms.common.calculators;
import lombok.RequiredArgsConstructor;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -43,13 +42,7 @@ public class PermissionCalculator {
private final String objectName;
private final List<PermissionProcessor> processors;
private final LoadingCache<String, Tristate> cache = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Tristate>() {
@Override
public Tristate load(String s) {
return lookupPermissionValue(s);
}
});
private final LoadingCache<String, Tristate> cache = Caffeine.newBuilder().build(this::lookupPermissionValue);
public void invalidateCache() {
cache.invalidateAll();
@@ -57,7 +50,7 @@ public class PermissionCalculator {
public Tristate getPermissionValue(String permission) {
permission = permission.toLowerCase();
Tristate t = cache.getUnchecked(permission);
Tristate t = cache.get(permission);
plugin.getVerboseHandler().offer(objectName, permission, t);
plugin.getPermissionVault().offer(permission);
return t;
@@ -24,9 +24,8 @@ package me.lucko.luckperms.common.config;
import lombok.Getter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.common.api.delegates.LPConfigurationDelegate;
import me.lucko.luckperms.common.config.keys.EnduringKey;
@@ -35,27 +34,22 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public abstract class AbstractConfiguration implements LuckPermsConfiguration {
private final LoadingCache<ConfigKey<?>, Optional<Object>> cache = CacheBuilder.newBuilder()
.build(new CacheLoader<ConfigKey<?>, Optional<Object>>() {
@Override
public Optional<Object> load(ConfigKey<?> key) {
return Optional.ofNullable(key.get(AbstractConfiguration.this));
}
});
private final LoadingCache<ConfigKey<?>, Optional<Object>> cache = Caffeine.newBuilder()
.build(key -> Optional.ofNullable(key.get(AbstractConfiguration.this)));
@Getter
private final LPConfigurationDelegate delegate = new LPConfigurationDelegate(this);
@SuppressWarnings("unchecked")
@Override
public <T> T get(ConfigKey<T> key) {
return (T) cache.getUnchecked(key).orElse(null);
return (T) cache.get(key).orElse(null);
}
@Override
public void loadAll() {
ConfigKeys.getAllKeys().forEach(cache::getUnchecked);
ConfigKeys.getAllKeys().forEach(cache::get);
}
@Override
@@ -24,40 +24,20 @@ package me.lucko.luckperms.common.constants;
import lombok.experimental.UtilityClass;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
@UtilityClass
public class Patterns {
private static final LoadingCache<String, Pattern> CACHE = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Pattern>() {
@Override
public Pattern load(String s) throws Exception {
return Pattern.compile(s);
}
@Override
public ListenableFuture<Pattern> reload(String s, Pattern pattern) {
return Futures.immediateFuture(pattern);
}
});
private static final LoadingCache<Map.Entry<String, String>, String> DELIMITER_CACHE = CacheBuilder.newBuilder()
.build(new CacheLoader<Map.Entry<String, String>, String>() {
@Override
public String load(Map.Entry<String, String> e) {
// note the reversed order
return "(?<!" + Pattern.quote(e.getValue()) + ")" + Pattern.quote(e.getKey());
}
private static final LoadingCache<String, Pattern> CACHE = Caffeine.newBuilder().build(Pattern::compile);
private static final LoadingCache<Map.Entry<String, String>, String> DELIMITER_CACHE = Caffeine.newBuilder()
.build(e -> {
// note the reversed order
return "(?<!" + Pattern.quote(e.getValue()) + ")" + Pattern.quote(e.getKey());
});
public static final Pattern COMMAND_SEPARATOR = Pattern.compile(" (?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)");
@@ -70,14 +50,14 @@ public class Patterns {
public static Pattern compile(String regex) {
try {
return CACHE.get(regex);
} catch (UncheckedExecutionException | ExecutionException e) {
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String buildDelimitedMatcher(String delim, String esc) {
return DELIMITER_CACHE.getUnchecked(Maps.immutableEntry(delim, esc));
return DELIMITER_CACHE.get(Maps.immutableEntry(delim, esc));
}
public static Pattern compileDelimitedMatcher(String delim, String esc) {
@@ -22,9 +22,8 @@
package me.lucko.luckperms.common.contexts;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextSet;
@@ -38,15 +37,10 @@ public class ContextManager<T> {
private final List<ContextCalculator<T>> calculators = new CopyOnWriteArrayList<>();
private final LoadingCache<T, ContextSet> cache = CacheBuilder.newBuilder()
private final LoadingCache<T, ContextSet> cache = Caffeine.newBuilder()
.weakKeys()
.expireAfterWrite(50L, TimeUnit.MILLISECONDS)
.build(new CacheLoader<T, ContextSet>() {
@Override
public ContextSet load(T t) {
return calculateApplicableContext(t, MutableContextSet.create()).makeImmutable();
}
});
.build(t -> calculateApplicableContext(t, MutableContextSet.create()).makeImmutable());
private MutableContextSet calculateApplicableContext(T subject, MutableContextSet accumulator) {
for (ContextCalculator<T> calculator : calculators) {
@@ -56,7 +50,7 @@ public class ContextManager<T> {
}
public ContextSet getApplicableContext(T subject) {
return cache.getUnchecked(subject);
return cache.get(subject);
}
public void registerCalculator(ContextCalculator<T> calculator) {
@@ -24,11 +24,9 @@ package me.lucko.luckperms.common.core;
import lombok.experimental.UtilityClass;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.base.Splitter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
@@ -38,33 +36,22 @@ import me.lucko.luckperms.common.core.model.Group;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
* Utility class to make Node(Builder) instances from serialised strings or existing Nodes
*/
@UtilityClass
public class NodeFactory {
private static final LoadingCache<String, Node> CACHE = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Node>() {
@Override
public Node load(String s) throws Exception {
return builderFromSerialisedNode(s, true).build();
}
});
private static final LoadingCache<String, Node> CACHE = Caffeine.newBuilder()
.build(s -> builderFromSerialisedNode(s, true).build());
private static final LoadingCache<String, Node> CACHE_NEGATED = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Node>() {
@Override
public Node load(String s) throws Exception {
return builderFromSerialisedNode(s, false).build();
}
});
private static final LoadingCache<String, Node> CACHE_NEGATED = Caffeine.newBuilder()
.build(s -> builderFromSerialisedNode(s, false).build());
public static Node fromSerialisedNode(String s, Boolean b) {
try {
return b ? CACHE.get(s) : CACHE_NEGATED.get(s);
} catch (UncheckedExecutionException | ExecutionException e) {
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
@@ -25,9 +25,8 @@ package me.lucko.luckperms.common.core;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
@@ -48,13 +47,7 @@ public class PriorityComparator implements Comparator<LocalizedNode> {
}
private final Collator collator = Collator.getInstance(Locale.ENGLISH);
private final LoadingCache<String, CollationKey> collationKeyCache = CacheBuilder.newBuilder()
.build(new CacheLoader<String, CollationKey>() {
@Override
public CollationKey load(String s) throws Exception {
return collator.getCollationKey(s);
}
});
private final LoadingCache<String, CollationKey> collationKeyCache = Caffeine.newBuilder().build(collator::getCollationKey);
@Override
public int compare(LocalizedNode one, LocalizedNode two) {
@@ -29,18 +29,18 @@ import lombok.Getter;
@AllArgsConstructor
public enum Dependency {
MYSQL_DRIVER("https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.6/mysql-connector-java-5.1.6.jar", "5.1.6", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource"),
POSTGRESQL_DRIVER("https://repo1.maven.org/maven2/org/postgresql/postgresql/9.4.1212/postgresql-9.4.1212.jar", "9.4.1212", "org.postgresql.ds.PGSimpleDataSource"),
H2_DRIVER("https://repo1.maven.org/maven2/com/h2database/h2/1.4.193/h2-1.4.193.jar", "1.4.193", "org.h2.Driver"),
SQLITE_DRIVER("https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.15.1/sqlite-jdbc-3.15.1.jar", "3.15.1", "org.sqlite.JDBC"),
HIKARI("https://repo1.maven.org/maven2/com/zaxxer/HikariCP/2.6.1/HikariCP-2.6.1.jar", "2.6.1", "com.zaxxer.hikari.HikariConfig"),
SLF4J_SIMPLE("https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.9/slf4j-simple-1.7.9.jar", "1.7.9", "org.slf4j.impl.SimpleLoggerFactory"),
SLF4J_API("https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.9/slf4j-api-1.7.9.jar", "1.7.9", "org.slf4j.helpers.BasicMarkerFactory"),
MONGODB_DRIVER("https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.4.1/mongo-java-driver-3.4.1.jar", "3.4.1", "com.mongodb.Mongo"),
JEDIS("https://github.com/lucko/jedis/releases/download/jedis-2.9.1-shaded/jedis-2.9.1-shaded.jar", "2.9.1-shaded", "redis.clients.jedis.shaded.Jedis");
CAFFEINE("https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/2.4.0/caffeine-2.4.0.jar", "2.4.0"),
MYSQL_DRIVER("https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.6/mysql-connector-java-5.1.6.jar", "5.1.6"),
POSTGRESQL_DRIVER("https://repo1.maven.org/maven2/org/postgresql/postgresql/9.4.1212/postgresql-9.4.1212.jar", "9.4.1212"),
H2_DRIVER("https://repo1.maven.org/maven2/com/h2database/h2/1.4.193/h2-1.4.193.jar", "1.4.193"),
SQLITE_DRIVER("https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.15.1/sqlite-jdbc-3.15.1.jar", "3.15.1"),
HIKARI("https://repo1.maven.org/maven2/com/zaxxer/HikariCP/2.6.1/HikariCP-2.6.1.jar", "2.6.1"),
SLF4J_SIMPLE("https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.9/slf4j-simple-1.7.9.jar", "1.7.9"),
SLF4J_API("https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.9/slf4j-api-1.7.9.jar", "1.7.9"),
MONGODB_DRIVER("https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.4.1/mongo-java-driver-3.4.1.jar", "3.4.1"),
JEDIS("https://github.com/lucko/jedis/releases/download/jedis-2.9.1-shaded/jedis-2.9.1-shaded.jar", "2.9.1-shaded");
private final String url;
private final String version;
private final String testClass;
}
@@ -22,12 +22,10 @@
package me.lucko.luckperms.common.managers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import me.lucko.luckperms.common.utils.Identifiable;
@@ -41,16 +39,7 @@ import java.util.Map;
*/
public abstract class AbstractManager<I, T extends Identifiable<I>> implements Manager<I, T> {
@SuppressWarnings("unchecked")
private static <I> I lowerCase(I i) {
if (i instanceof String) {
return (I) ((String) i).toLowerCase();
} else {
return i;
}
}
private final LoadingCache<I, T> objects = CacheBuilder.newBuilder()
private final LoadingCache<I, T> objects = Caffeine.newBuilder()
.build(new CacheLoader<I, T>() {
@Override
public T load(I i) {
@@ -58,8 +47,8 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> implements M
}
@Override
public ListenableFuture<T> reload(I i, T t) {
return Futures.immediateFuture(t); // Never needs to be refreshed.
public T reload(I i, T t) {
return t; // Never needs to be refreshed.
}
});
@@ -70,7 +59,7 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> implements M
@Override
public T getOrMake(I id) {
return objects.getUnchecked(lowerCase(id));
return objects.get(lowerCase(id));
}
@Override
@@ -102,4 +91,13 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> implements M
objects.invalidateAll();
}
@SuppressWarnings("unchecked")
private static <I> I lowerCase(I i) {
if (i instanceof String) {
return (I) ((String) i).toLowerCase();
} else {
return i;
}
}
}