Refactor sponge cache invalidation

This commit is contained in:
Luck 2017-09-29 23:21:12 +01:00
parent ec75fdddb5
commit 1bd7e5c9c4
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
10 changed files with 73 additions and 108 deletions

View File

@ -85,9 +85,5 @@ public interface LPPermissionService {
Contexts calculateContexts(ImmutableContextSet contextSet);
void invalidatePermissionCaches();
void invalidateParentCaches();
void invalidateOptionCaches();
void invalidateAllCaches(LPSubject.CacheLevel cacheLevel);
}

View File

@ -86,4 +86,17 @@ public interface LPSubject {
}
void invalidateCaches(CacheLevel cacheLevel);
/**
* The level of cache for invalidation
*
* Invalidating at {@link #PARENT} will also invalidate at
* {@link #PERMISSION} and {@link #OPTION}, and invalidating at
* {@link #PERMISSION} will also invalidate at {@link #OPTION}.
*/
enum CacheLevel {
PARENT, PERMISSION, OPTION
}
}

View File

@ -78,6 +78,7 @@ import me.lucko.luckperms.sponge.managers.SpongeUserManager;
import me.lucko.luckperms.sponge.messaging.SpongeMessagingFactory;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
import me.lucko.luckperms.sponge.service.model.LPSubject;
import me.lucko.luckperms.sponge.service.model.LPSubjectCollection;
import me.lucko.luckperms.sponge.service.persisted.PersistedCollection;
import me.lucko.luckperms.sponge.tasks.ServiceCacheHousekeepingTask;
@ -332,7 +333,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
((PersistedCollection) collection).loadAll();
}
}
service.invalidateParentCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
}
@Override

View File

@ -27,7 +27,6 @@ package me.lucko.luckperms.sponge.managers;
import lombok.Getter;
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.base.Preconditions;
@ -71,17 +70,7 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
private SubjectCollection spongeProxy = null;
private final LoadingCache<String, SpongeGroup> objects = Caffeine.newBuilder()
.build(new CacheLoader<String, SpongeGroup>() {
@Override
public SpongeGroup load(String i) {
return apply(i);
}
@Override
public SpongeGroup reload(String i, SpongeGroup t) {
return t; // Never needs to be refreshed.
}
});
.build(this::apply);
private final LoadingCache<String, LPSubject> subjectLoadingCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)

View File

@ -27,7 +27,6 @@ package me.lucko.luckperms.sponge.managers;
import lombok.Getter;
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.base.Preconditions;
@ -72,17 +71,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
private SubjectCollection spongeProxy = null;
private final LoadingCache<UserIdentifier, SpongeUser> objects = Caffeine.newBuilder()
.build(new CacheLoader<UserIdentifier, SpongeUser>() {
@Override
public SpongeUser load(UserIdentifier i) {
return apply(i);
}
@Override
public SpongeUser reload(UserIdentifier i, SpongeUser t) {
return t; // Never needs to be refreshed.
}
});
.build(this::apply);
private final LoadingCache<UUID, LPSubject> subjectLoadingCache = Caffeine.<UUID, LPSubject>newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)

View File

@ -126,10 +126,15 @@ public class SpongeGroup extends Group {
this.subjectData = new LuckPermsSubjectData(true, plugin.getService(), parent, this);
this.transientSubjectData = new LuckPermsSubjectData(false, plugin.getService(), parent, this);
parent.getStateListeners().add(this::invalidateCaches);
parent.getStateListeners().add(() -> invalidateCaches(CacheLevel.PERMISSION));
}
public void invalidateCaches() {
@Override
public void invalidateCaches(CacheLevel type) {
if (type == CacheLevel.OPTION) {
return; // don't invalidate for option changes
}
permissionCache.invalidateAll();
parentCache.invalidateAll();
}

View File

@ -70,7 +70,7 @@ public class SpongeUser extends User {
return this.spongeData;
}
public static class UserSubject implements LPSubject {
public static final class UserSubject implements LPSubject {
private final SpongeUser parent;
private final LPSpongePlugin plugin;
@ -187,6 +187,12 @@ public class SpongeUser extends User {
public ImmutableContextSet getActiveContextSet() {
return plugin.getContextManager().getApplicableContext(this.sponge());
}
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
parent.getUserData().invalidateCache();
}
}
}

View File

@ -34,23 +34,15 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MapMaker;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.caching.UserCache;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.contexts.SpongeCalculatorLink;
import me.lucko.luckperms.sponge.managers.SpongeGroupManager;
import me.lucko.luckperms.sponge.managers.SpongeUserManager;
import me.lucko.luckperms.sponge.model.SpongeGroup;
import me.lucko.luckperms.sponge.service.calculated.CalculatedSubjectData;
import me.lucko.luckperms.sponge.service.calculated.OptionLookup;
import me.lucko.luckperms.sponge.service.calculated.PermissionLookup;
import me.lucko.luckperms.sponge.service.legacy.LegacyDataMigrator;
import me.lucko.luckperms.sponge.service.model.LPPermissionDescription;
import me.lucko.luckperms.sponge.service.model.LPPermissionService;
@ -95,11 +87,6 @@ public class LuckPermsService implements LPPermissionService {
private final PersistedCollection defaultSubjects;
private final Set<LPPermissionDescription> descriptionSet;
private final Set<LoadingCache<PermissionLookup, Tristate>> localPermissionCaches;
private final Set<LoadingCache<ImmutableContextSet, ImmutableList<SubjectReference>>> localParentCaches;
private final Set<LoadingCache<OptionLookup, Optional<String>>> localOptionCaches;
private final Set<CalculatedSubjectData> localDataCaches;
@Getter(value = AccessLevel.NONE)
private final LoadingCache<String, LPSubjectCollection> collections = Caffeine.newBuilder()
.build(s -> new PersistedCollection(this, s));
@ -108,11 +95,6 @@ public class LuckPermsService implements LPPermissionService {
this.plugin = plugin;
this.spongeProxy = ProxyFactory.toSponge(this);
localPermissionCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
localParentCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
localOptionCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
localDataCaches = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
storage = new SubjectStorage(this, new File(plugin.getDataDirectory(), "sponge-data"));
new LegacyDataMigrator(plugin, new File(plugin.getDataDirectory(), "local"), storage).run();
@ -254,44 +236,15 @@ public class LuckPermsService implements LPPermissionService {
}
@Override
public void invalidatePermissionCaches() {
for (LoadingCache<PermissionLookup, Tristate> c : localPermissionCaches) {
c.invalidateAll();
}
for (CalculatedSubjectData subjectData : localDataCaches) {
subjectData.invalidateLookupCache();
public void invalidateAllCaches(LPSubject.CacheLevel cacheLevel) {
for (LPSubjectCollection collection : collections.asMap().values()) {
for (LPSubject subject : collection.getLoadedSubjects()) {
subject.invalidateCaches(cacheLevel);
}
}
plugin.getCalculatorFactory().invalidateAll();
for (User user : plugin.getUserManager().getAll().values()) {
UserCache userCache = user.getUserData();
userCache.invalidateCache();
}
for (SpongeGroup group : plugin.getGroupManager().getAll().values()) {
group.sponge().invalidateCaches();
}
}
@Override
public void invalidateParentCaches() {
for (LoadingCache<ImmutableContextSet, ImmutableList<SubjectReference>> c : localParentCaches) {
c.invalidateAll();
}
invalidateOptionCaches();
invalidatePermissionCaches();
}
@Override
public void invalidateOptionCaches() {
for (LoadingCache<OptionLookup, Optional<String>> c : localOptionCaches) {
c.invalidateAll();
}
for (User user : plugin.getUserManager().getAll().values()) {
UserCache userCache = user.getUserData();
userCache.invalidateCache();
if (cacheLevel != LPSubject.CacheLevel.OPTION) {
plugin.getCalculatorFactory().invalidateAll();
}
}
}

View File

@ -110,7 +110,7 @@ public class CalculatedSubjectData implements LPSubjectData {
permissions.put(e.getKey(), new ConcurrentHashMap<>(e.getValue()));
}
permissionCache.invalidateAll();
service.invalidatePermissionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PERMISSION);
}
public void replaceParents(Map<ImmutableContextSet, List<SubjectReference>> map) {
@ -120,7 +120,7 @@ public class CalculatedSubjectData implements LPSubjectData {
set.addAll(e.getValue());
parents.put(e.getKey(), set);
}
service.invalidateParentCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
}
public void replaceOptions(Map<ImmutableContextSet, Map<String, String>> map) {
@ -128,7 +128,7 @@ public class CalculatedSubjectData implements LPSubjectData {
for (Map.Entry<ImmutableContextSet, Map<String, String>> e : map.entrySet()) {
options.put(e.getKey(), new ConcurrentHashMap<>(e.getValue()));
}
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.OPTION);
}
@Override
@ -152,7 +152,7 @@ public class CalculatedSubjectData implements LPSubjectData {
}
if (b) {
permissionCache.invalidateAll();
service.invalidatePermissionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PERMISSION);
}
return CompletableFuture.completedFuture(b);
}
@ -164,7 +164,7 @@ public class CalculatedSubjectData implements LPSubjectData {
} else {
permissions.clear();
permissionCache.invalidateAll();
service.invalidatePermissionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PERMISSION);
return CompletableFuture.completedFuture(true);
}
}
@ -179,7 +179,7 @@ public class CalculatedSubjectData implements LPSubjectData {
permissions.remove(contexts);
if (!perms.isEmpty()) {
permissionCache.invalidateAll();
service.invalidatePermissionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PERMISSION);
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
@ -199,7 +199,7 @@ public class CalculatedSubjectData implements LPSubjectData {
Set<SubjectReference> set = parents.computeIfAbsent(contexts, c -> ConcurrentHashMap.newKeySet());
boolean b = set.add(parent);
if (b) {
service.invalidateParentCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
}
return CompletableFuture.completedFuture(b);
}
@ -209,7 +209,7 @@ public class CalculatedSubjectData implements LPSubjectData {
Set<SubjectReference> set = parents.get(contexts);
boolean b = set != null && set.remove(parent);
if (b) {
service.invalidateParentCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
}
return CompletableFuture.completedFuture(b);
}
@ -220,7 +220,7 @@ public class CalculatedSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false);
} else {
parents.clear();
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
return CompletableFuture.completedFuture(true);
}
}
@ -233,7 +233,7 @@ public class CalculatedSubjectData implements LPSubjectData {
}
parents.remove(contexts);
service.invalidateParentCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.PARENT);
return CompletableFuture.completedFuture(!set.isEmpty());
}
@ -251,7 +251,7 @@ public class CalculatedSubjectData implements LPSubjectData {
Map<String, String> options = this.options.computeIfAbsent(contexts, c -> new ConcurrentHashMap<>());
boolean b = !stringEquals(options.put(key.toLowerCase(), value), value);
if (b) {
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.OPTION);
}
return CompletableFuture.completedFuture(b);
}
@ -261,7 +261,7 @@ public class CalculatedSubjectData implements LPSubjectData {
Map<String, String> options = this.options.get(contexts);
boolean b = options != null && options.remove(key.toLowerCase()) != null;
if (b) {
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.OPTION);
}
return CompletableFuture.completedFuture(b);
}
@ -272,7 +272,7 @@ public class CalculatedSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false);
} else {
options.clear();
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.OPTION);
return CompletableFuture.completedFuture(true);
}
}
@ -285,7 +285,7 @@ public class CalculatedSubjectData implements LPSubjectData {
}
options.remove(contexts);
service.invalidateOptionCaches();
service.invalidateAllCaches(LPSubject.CacheLevel.OPTION);
return CompletableFuture.completedFuture(!map.isEmpty());
}

View File

@ -98,14 +98,27 @@ public class PersistedSubject implements LPSubject {
this.service = service;
this.parentCollection = parentCollection;
this.subjectData = new PersistedSubjectData(service, "local:" + parentCollection.getIdentifier() + "/" + identifier + "(p)", this);
this.transientSubjectData = new CalculatedSubjectData(this, service, "local:" + parentCollection.getIdentifier() + "/" + identifier + "(t)");
this.subjectData = new PersistedSubjectData(service, parentCollection.getIdentifier() + "/" + identifier + "/p", this);
this.transientSubjectData = new CalculatedSubjectData(this, service, parentCollection.getIdentifier() + "/" + identifier + "/t");
}
service.getLocalDataCaches().add(subjectData);
service.getLocalDataCaches().add(transientSubjectData);
service.getLocalPermissionCaches().add(permissionLookupCache);
service.getLocalParentCaches().add(parentLookupCache);
service.getLocalOptionCaches().add(optionLookupCache);
@Override
public void invalidateCaches(CacheLevel type) {
optionLookupCache.invalidateAll();
if (type == CacheLevel.OPTION) {
return;
}
permissionLookupCache.invalidateAll();
subjectData.invalidateLookupCache();
transientSubjectData.invalidateLookupCache();
if (type == CacheLevel.PERMISSION) {
return;
}
parentLookupCache.invalidateAll();
}
@Override