Use a separate fork join pool for cache loading operations

This commit is contained in:
Luck
2019-03-05 12:35:29 +00:00
Unverified
parent d1ca7684d6
commit 3726f6de41
15 changed files with 109 additions and 78 deletions
@@ -27,7 +27,6 @@ package me.lucko.luckperms.common.cacheddata;
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Contexts;
@@ -41,6 +40,7 @@ import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.CaffeineFactory;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -64,14 +64,14 @@ public abstract class AbstractCachedData implements CachedData {
/**
* The cache used for {@link PermissionCache} instances.
*/
private final AsyncLoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
private final AsyncLoadingCache<Contexts, PermissionCache> permission = CaffeineFactory.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES)
.buildAsync(new PermissionCacheLoader());
/**
* The cache used for {@link MetaCache} instances.
*/
private final AsyncLoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
private final AsyncLoadingCache<MetaContexts, MetaCache> meta = CaffeineFactory.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES)
.buildAsync(new MetaCacheLoader());
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.group;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
@@ -43,6 +42,7 @@ import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.CaffeineFactory;
import java.util.ArrayList;
import java.util.List;
@@ -55,7 +55,7 @@ public class GroupMainCommand extends MainCommand<Group, String> {
// this helps prevent race conditions where commands are being executed concurrently
// and overriding each other.
// it's not a great solution, but it mostly works.
private final LoadingCache<String, ReentrantLock> locks = Caffeine.newBuilder()
private final LoadingCache<String, ReentrantLock> locks = CaffeineFactory.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.build(key -> new ReentrantLock());
@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.commands.misc;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateBuilder;
@@ -48,6 +47,7 @@ import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
@@ -55,7 +55,7 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class BulkUpdateCommand extends SingleCommand {
private final Cache<String, BulkUpdate> pendingOperations = Caffeine.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
private final Cache<String, BulkUpdate> pendingOperations = CaffeineFactory.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build();
public BulkUpdateCommand(LocaleManager locale) {
super(CommandSpec.BULK_UPDATE.localize(locale), "BulkUpdate", CommandPermission.BULK_UPDATE, Predicates.alwaysFalse());
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.track;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
@@ -37,6 +36,7 @@ import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.CaffeineFactory;
import java.util.ArrayList;
import java.util.List;
@@ -49,7 +49,7 @@ public class TrackMainCommand extends MainCommand<Track, String> {
// this helps prevent race conditions where commands are being executed concurrently
// and overriding each other.
// it's not a great solution, but it mostly works.
private final LoadingCache<String, ReentrantLock> locks = Caffeine.newBuilder()
private final LoadingCache<String, ReentrantLock> locks = CaffeineFactory.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.build(key -> new ReentrantLock());
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.user;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
@@ -46,6 +45,7 @@ import me.lucko.luckperms.common.model.UserIdentifier;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.common.util.Uuids;
import java.util.List;
@@ -60,7 +60,7 @@ public class UserMainCommand extends MainCommand<User, UserIdentifier> {
// this helps prevent race conditions where commands are being executed concurrently
// and overriding each other.
// it's not a great solution, but it mostly works.
private final LoadingCache<UUID, ReentrantLock> locks = Caffeine.newBuilder()
private final LoadingCache<UUID, ReentrantLock> locks = CaffeineFactory.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.build(key -> new ReentrantLock());
@@ -25,12 +25,12 @@
package me.lucko.luckperms.common.primarygroup;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.util.CaffeineFactory;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -44,7 +44,7 @@ import java.util.concurrent.TimeUnit;
public abstract class ContextualHolder extends StoredHolder {
// cache lookups
private final LoadingCache<Contexts, Optional<String>> cache = Caffeine.newBuilder()
private final LoadingCache<Contexts, Optional<String>> cache = CaffeineFactory.newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES)
.build(this::calculateValue);
@@ -0,0 +1,27 @@
package me.lucko.luckperms.common.util;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.ForkJoinPool;
public final class CaffeineFactory {
private CaffeineFactory() {}
/**
* Our own fork join pool for LuckPerms cache operations.
*
* By default, Caffeine uses the ForkJoinPool.commonPool instance.
* However... ForkJoinPool is a fixed size pool limited by Runtime.availableProcessors.
* Some (bad) plugins incorrectly use this pool for i/o operations, make calls to Thread.sleep
* or otherwise block waiting for something else to complete. This prevents the LP cache loading
* operations from running.
*
* By using our own pool, we ensure this will never happen.
*/
private static final ForkJoinPool loaderPool = new ForkJoinPool();
public static Caffeine<Object, Object> newBuilder() {
return Caffeine.newBuilder().executor(loaderPool);
}
}