Fix group changes via the API not properly invalidating caches (#1534)

This commit is contained in:
Luck 2019-05-20 10:42:48 +01:00
parent 2e16b15b0e
commit 8d8024ba5e
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
21 changed files with 193 additions and 102 deletions

View File

@ -26,10 +26,12 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.LuckPerms;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
@ -110,6 +112,15 @@ public interface LuckPermsApi {
*/
@NonNull TrackManager getTrackManager();
/**
* Gets the {@link CachedDataManager}, responsible for managing
* {@link CachedData} instances.
*
* @return the cached data manager
* @since 4.5
*/
@NonNull CachedDataManager getCachedDataManager();
/**
* Schedules the execution of an update task, and returns an encapsulation
* of the task as a {@link CompletableFuture}.

View File

@ -412,6 +412,14 @@ public interface CachedData {
*/
void invalidateMeta();
/**
* Invalidates all cached {@link PermissionData} and {@link MetaData}
* instances.
*
* @since 4.5
*/
void invalidate();
/**
* Invalidates all of the underlying Permission calculators.
*

View File

@ -0,0 +1,53 @@
/*
* 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.api.manager;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.CachedData;
/**
* Represents an object responsible for managing {@link CachedData} instances.
*
* @since 4.5
*/
public interface CachedDataManager {
/**
* Invalidate the {@link CachedData} instances for all loaded {@link User}s.
*
* @see CachedData#invalidate()
*/
void invalidateAllUserCaches();
/**
* Invalidate the {@link CachedData} instances for all loaded {@link Group}s.
*
* @see CachedData#invalidate()
*/
void invalidateAllGroupCaches();
}

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.UuidCache;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
@ -41,6 +42,7 @@ import me.lucko.luckperms.api.messenger.MessengerProvider;
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.api.platform.PlatformInfo;
import me.lucko.luckperms.common.api.implementation.ApiActionLogger;
import me.lucko.luckperms.common.api.implementation.ApiCachedDataManager;
import me.lucko.luckperms.common.api.implementation.ApiContextManager;
import me.lucko.luckperms.common.api.implementation.ApiGroupManager;
import me.lucko.luckperms.common.api.implementation.ApiMessagingService;
@ -71,6 +73,7 @@ public class LuckPermsApiProvider implements LuckPermsApi {
private final UserManager userManager;
private final GroupManager groupManager;
private final TrackManager trackManager;
private final CachedDataManager cachedDataManager;
private final ActionLogger actionLogger;
private final ContextManager contextManager;
private final MetaStackFactory metaStackFactory;
@ -82,6 +85,7 @@ public class LuckPermsApiProvider implements LuckPermsApi {
this.userManager = new ApiUserManager(plugin, plugin.getUserManager());
this.groupManager = new ApiGroupManager(plugin, plugin.getGroupManager());
this.trackManager = new ApiTrackManager(plugin, plugin.getTrackManager());
this.cachedDataManager = new ApiCachedDataManager(plugin.getUserManager(), plugin.getGroupManager());
this.actionLogger = new ApiActionLogger(plugin);
this.contextManager = new ApiContextManager(plugin, plugin.getContextManager());
this.metaStackFactory = new ApiMetaStackFactory(plugin);
@ -107,6 +111,11 @@ public class LuckPermsApiProvider implements LuckPermsApi {
return this.trackManager;
}
@Override
public @NonNull CachedDataManager getCachedDataManager() {
return this.cachedDataManager;
}
@Override
public @NonNull CompletableFuture<Void> runUpdateTask() {
return this.plugin.getSyncTaskBuffer().request();

View File

@ -0,0 +1,51 @@
/*
* 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.api.implementation;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.common.model.manager.group.GroupManager;
import me.lucko.luckperms.common.model.manager.user.UserManager;
public class ApiCachedDataManager implements CachedDataManager {
private final UserManager<?> userManager;
private final GroupManager<?> groupManager;
public ApiCachedDataManager(UserManager<?> userManager, GroupManager<?> groupManager) {
this.userManager = userManager;
this.groupManager = groupManager;
}
@Override
public void invalidateAllUserCaches() {
this.userManager.invalidateAllUserCaches();
}
@Override
public void invalidateAllGroupCaches() {
this.groupManager.invalidateAllGroupCaches();
}
}

View File

@ -75,7 +75,12 @@ public class ApiGroupManager extends ApiAbstractManager<Group, me.lucko.luckperm
@Override
public @NonNull CompletableFuture<Void> saveGroup(me.lucko.luckperms.api.@NonNull Group group) {
Objects.requireNonNull(group, "group");
return this.plugin.getStorage().saveGroup(ApiGroup.cast(group));
return this.plugin.getStorage().saveGroup(ApiGroup.cast(group)).thenRun(() -> {
// invalidate caches - they have potentially been affected by
// this change.
this.plugin.getGroupManager().invalidateAllGroupCaches();
this.plugin.getUserManager().invalidateAllUserCaches();
});
}
@Override
@ -84,7 +89,13 @@ public class ApiGroupManager extends ApiAbstractManager<Group, me.lucko.luckperm
if (group.getName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return this.plugin.getStorage().deleteGroup(ApiGroup.cast(group), DeletionCause.API);
return this.plugin.getStorage().deleteGroup(ApiGroup.cast(group), DeletionCause.API).thenRun(() -> {
// invalidate caches - they have potentially been affected by
// this change.
this.plugin.getGroupManager().invalidateAllGroupCaches();
this.plugin.getUserManager().invalidateAllUserCaches();
});
}
@Override

View File

@ -31,19 +31,13 @@ import me.lucko.luckperms.api.Log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.common.api.ApiUtils;
import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.Storage;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@ -69,10 +63,12 @@ public class ApiStorage implements me.lucko.luckperms.api.Storage {
}
private final LuckPermsPlugin plugin;
private final LuckPermsApiProvider apiProvider;
private final Storage handle;
public ApiStorage(LuckPermsPlugin plugin, Storage handle) {
public ApiStorage(LuckPermsPlugin plugin, LuckPermsApiProvider apiProvider, Storage handle) {
this.plugin = plugin;
this.apiProvider = apiProvider;
this.handle = handle;
}
@ -98,155 +94,130 @@ public class ApiStorage implements me.lucko.luckperms.api.Storage {
@Override
public @NonNull CompletableFuture<Boolean> logAction(@NonNull LogEntry entry) {
Objects.requireNonNull(entry, "entry");
return this.handle.logAction(entry)
return this.apiProvider.getActionLogger().submitToStorage(entry)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Log> getLog() {
return this.handle.getLog().<Log>thenApply(ApiLog::new).exceptionally(consumeExceptionToNull());
return this.apiProvider.getActionLogger().getLog().exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> loadUser(@NonNull UUID uuid, String username) {
Objects.requireNonNull(uuid, "uuid");
username = ApiUtils.checkUsername(username, this.plugin);
if (this.plugin.getUserManager().getIfLoaded(uuid) == null) {
this.plugin.getUserManager().getHouseKeeper().registerApiUsage(uuid);
}
return this.handle.loadUser(uuid, username)
return this.apiProvider.getUserManager().loadUser(uuid, username)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveUser(@NonNull User user) {
Objects.requireNonNull(user, "user");
return this.handle.saveUser(ApiUser.cast(user))
return this.apiProvider.getUserManager().saveUser(user)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Set<UUID>> getUniqueUsers() {
return this.handle.getUniqueUsers().exceptionally(consumeExceptionToNull());
return this.apiProvider.getUserManager().getUniqueUsers().exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@NonNull String permission) {
Objects.requireNonNull(permission, "permission");
return this.handle.getUsersWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).exceptionally(consumeExceptionToNull());
return this.apiProvider.getUserManager().getWithPermission(permission).exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> createAndLoadGroup(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.createAndLoadGroup(ApiUtils.checkName(name), CreationCause.API)
return this.apiProvider.getGroupManager().createAndLoadGroup(name)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadGroup(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.loadGroup(ApiUtils.checkName(name))
return this.apiProvider.getGroupManager().loadGroup(name)
.thenApply(Optional::isPresent)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadAllGroups() {
return this.handle.loadAllGroups()
return this.apiProvider.getGroupManager().loadAllGroups()
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveGroup(@NonNull Group group) {
Objects.requireNonNull(group, "group");
return this.handle.saveGroup(ApiGroup.cast(group))
return this.apiProvider.getGroupManager().saveGroup(group)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> deleteGroup(@NonNull Group group) {
Objects.requireNonNull(group, "group");
if (group.getName().equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return this.handle.deleteGroup(ApiGroup.cast(group), DeletionCause.API)
return this.apiProvider.getGroupManager().deleteGroup(group)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@NonNull String permission) {
Objects.requireNonNull(permission, "permission");
return this.handle.getGroupsWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).exceptionally(consumeExceptionToNull());
return this.apiProvider.getGroupManager().getWithPermission(permission)
.exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<Boolean> createAndLoadTrack(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.createAndLoadTrack(ApiUtils.checkName(name), CreationCause.API)
return this.apiProvider.getTrackManager().createAndLoadTrack(name)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadTrack(@NonNull String name) {
Objects.requireNonNull(name, "name");
return this.handle.loadTrack(ApiUtils.checkName(name))
return this.apiProvider.getTrackManager().loadTrack(name)
.thenApply(Optional::isPresent)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> loadAllTracks() {
return this.handle.loadAllTracks()
return this.apiProvider.getTrackManager().loadAllTracks()
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveTrack(@NonNull Track track) {
Objects.requireNonNull(track, "track");
return this.handle.saveTrack(ApiTrack.cast(track))
return this.apiProvider.getTrackManager().saveTrack(track)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> deleteTrack(@NonNull Track track) {
Objects.requireNonNull(track, "track");
return this.handle.deleteTrack(ApiTrack.cast(track), DeletionCause.API)
return this.apiProvider.getTrackManager().deleteTrack(track)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<Boolean> saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
Objects.requireNonNull(username, "username");
Objects.requireNonNull(uuid, "uuid");
return this.handle.savePlayerData(uuid, ApiUtils.checkUsername(username, this.plugin))
return this.apiProvider.getUserManager().savePlayerData(uuid, username)
.thenApply(r -> true)
.exceptionally(consumeExceptionToFalse());
}
@Override
public @NonNull CompletableFuture<UUID> getUUID(@NonNull String username) {
Objects.requireNonNull(username, "username");
return this.handle.getPlayerUuid(ApiUtils.checkUsername(username, this.plugin));
return this.apiProvider.getUserManager().lookupUuid(username).exceptionally(consumeExceptionToNull());
}
@Override
public @NonNull CompletableFuture<String> getName(@NonNull UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
return this.handle.getPlayerName(uuid);
return this.apiProvider.getUserManager().lookupUsername(uuid).exceptionally(consumeExceptionToNull());
}
}

View File

@ -374,16 +374,17 @@ public abstract class AbstractCachedData implements CachedData {
}
@Override
public final void invalidatePermissionCalculators() {
this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache);
}
public final void invalidate() {
invalidatePermissions();
invalidateMeta();
}
public final void doCacheCleanup() {
@Override
public final void invalidatePermissionCalculators() {
this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache);
}
public final void performCacheCleanup() {
this.permission.synchronous().cleanUp();
this.meta.synchronous().cleanUp();
}

View File

@ -211,18 +211,11 @@ public abstract class PermissionHolder {
*/
public abstract HolderType getType();
/**
* Invalidates the holder's cached data.
*/
public void invalidateCachedData() {
getCachedData().invalidate();
}
protected void invalidateCache() {
this.enduringNodes.invalidate();
this.transientNodes.invalidate();
invalidateCachedData();
getCachedData().invalidate();
getPlugin().getEventFactory().handleDataRecalculate(this);
}

View File

@ -77,11 +77,6 @@ public abstract class AbstractManager<I, C extends Identifiable<I>, T extends C>
}
}
@Override
public void unloadAll() {
this.objects.clear();
}
protected I sanitizeIdentifier(I i) {
return i;
}

View File

@ -86,9 +86,4 @@ public interface Manager<I, C extends Identifiable<I>, T extends C> extends Func
*/
void unload(C object);
/**
* Unloads all objects from the manager
*/
void unloadAll();
}

View File

@ -26,7 +26,6 @@
package me.lucko.luckperms.common.model.manager.group;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.manager.AbstractManager;
import java.util.Optional;
@ -67,11 +66,11 @@ public abstract class AbstractGroupManager<T extends Group> extends AbstractMana
@Override
public void invalidateAllGroupCaches() {
getAll().values().forEach(PermissionHolder::invalidateCachedData);
getAll().values().forEach(g -> g.getCachedData().invalidate());
}
@Override
public void invalidateAllPermissionCalculators() {
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
getAll().values().forEach(g -> g.getCachedData().invalidatePermissionCalculators());
}
}

View File

@ -31,7 +31,6 @@ import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.model.UserIdentifier;
import me.lucko.luckperms.common.model.manager.AbstractManager;
@ -165,12 +164,12 @@ public abstract class AbstractUserManager<T extends User> extends AbstractManage
@Override
public void invalidateAllUserCaches() {
getAll().values().forEach(PermissionHolder::invalidateCachedData);
getAll().values().forEach(u -> u.getCachedData().invalidate());
}
@Override
public void invalidateAllPermissionCalculators() {
getAll().values().forEach(p -> p.getCachedData().invalidatePermissionCalculators());
getAll().values().forEach(u -> u.getCachedData().invalidatePermissionCalculators());
}
/**

View File

@ -217,7 +217,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
} catch (Exception e) {
throw reportException(uuid.toString(), e);
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@ -273,7 +272,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
} catch (Exception e) {
throw reportException(name, e);
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return group;
@ -306,7 +304,6 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
throw reportException(name, e);
} finally {
if (group != null) {
group.invalidateCachedData();
group.getIoLock().unlock();
}
}

View File

@ -297,7 +297,6 @@ public class MongoStorage implements StorageImplementation {
}
}
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@ -368,7 +367,6 @@ public class MongoStorage implements StorageImplementation {
}
}
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return group;
@ -398,7 +396,6 @@ public class MongoStorage implements StorageImplementation {
}
} finally {
if (group != null) {
group.invalidateCachedData();
group.getIoLock().unlock();
}
}

View File

@ -394,7 +394,6 @@ public class SqlStorage implements StorageImplementation {
}
}
} finally {
user.invalidateCachedData();
user.getIoLock().unlock();
}
return user;
@ -636,7 +635,6 @@ public class SqlStorage implements StorageImplementation {
group.clearNodes();
}
} finally {
group.invalidateCachedData();
group.getIoLock().unlock();
}
return Optional.of(group);

View File

@ -39,10 +39,10 @@ public class CacheHousekeepingTask implements Runnable {
@Override
public void run() {
for (User user : this.plugin.getUserManager().getAll().values()) {
user.getCachedData().doCacheCleanup();
user.getCachedData().performCacheCleanup();
}
for (Group group : this.plugin.getGroupManager().getAll().values()) {
group.getCachedData().doCacheCleanup();
group.getCachedData().performCacheCleanup();
}
}
}

View File

@ -74,9 +74,7 @@ public interface LPSubject {
Optional<String> getOption(ImmutableContextSet contexts, String key);
default void performCleanup() {
}
void performCacheCleanup();
void invalidateCaches();

View File

@ -313,8 +313,8 @@ public abstract class CalculatedSubject implements LPSubject {
}
@Override
public void performCleanup() {
this.cachedData.doCacheCleanup();
public void performCacheCleanup() {
this.cachedData.performCacheCleanup();
}
@Override

View File

@ -166,10 +166,15 @@ public abstract class PermissionHolderSubject<T extends PermissionHolder> implem
return this.plugin.getService().getRootDefaults().getOption(contexts, s);
}
@Override
public void performCacheCleanup() {
// do nothing, permission holders are "cleaned up" by a different task
}
@Override
public void invalidateCaches() {
// invalidate for all changes
this.parent.invalidateCachedData();
this.parent.getCachedData().invalidate();
}
}

View File

@ -40,7 +40,7 @@ public class ServiceCacheHousekeepingTask implements Runnable {
public void run() {
for (LPSubjectCollection collection : this.service.getLoadedCollections().values()) {
for (LPSubject subject : collection.getLoadedSubjects()) {
subject.performCleanup();
subject.performCacheCleanup();
}
}
}