Refactor the way holder caches are invalidated in order to improve consistency (#734)

This commit is contained in:
Luck 2018-05-03 19:35:44 +01:00
parent b8a1871cf1
commit a6facf7492
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
22 changed files with 231 additions and 260 deletions

View File

@ -55,11 +55,6 @@ public class BukkitConfigAdapter extends AbstractConfigurationAdapter implements
this.configuration = YamlConfiguration.loadConfiguration(this.file);
}
@Override
public boolean contains(String path) {
return this.configuration.contains(path);
}
@Override
public String getString(String path, String def) {
return this.configuration.getString(path, def);

View File

@ -403,7 +403,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
void holderSave(PermissionHolder holder) {
if (holder.getType().isUser()) {
User u = (User) holder;
this.plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), this.plugin.getBootstrap().getScheduler().async());
this.plugin.getStorage().saveUser(u).thenRunAsync(() -> u.reloadCachedData(), this.plugin.getBootstrap().getScheduler().async());
}
if (holder.getType().isGroup()) {
Group g = (Group) holder;

View File

@ -61,11 +61,6 @@ public class BungeeConfigAdapter extends AbstractConfigurationAdapter implements
}
}
@Override
public boolean contains(String path) {
return this.configuration.contains(path);
}
@Override
public String getString(String path, String def) {
return this.configuration.getString(path, def);

View File

@ -98,7 +98,7 @@ public class ApiPermissionHolder implements me.lucko.luckperms.api.PermissionHol
@Nonnull
@Override
public CompletableFuture<Void> refreshCachedData() {
return this.handle.getRefreshBuffer().request();
return this.handle.reloadCachedData();
}
@Nonnull

View File

@ -99,7 +99,7 @@ public final class ApiUser extends ApiPermissionHolder implements me.lucko.luckp
@Override
@Deprecated
public void refreshPermissions() {
this.handle.getRefreshBuffer().requestDirectly();
this.handle.reloadCachedData().join();
}
@Override

View File

@ -25,9 +25,9 @@
package me.lucko.luckperms.common.caching;
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Contexts;
@ -43,7 +43,6 @@ import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@ -51,6 +50,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Abstract implementation of {@link CachedData}.
@ -65,16 +65,16 @@ public abstract class AbstractCachedData implements CachedData {
/**
* The cache used for {@link PermissionCache} instances.
*/
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
private final AsyncLoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES)
.build(new PermissionCacheLoader());
.buildAsync(new PermissionCacheLoader());
/**
* The cache used for {@link MetaCache} instances.
*/
private final LoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
private final AsyncLoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
.expireAfterAccess(2, TimeUnit.MINUTES)
.build(new MetaCacheLoader());
.buildAsync(new MetaCacheLoader());
public AbstractCachedData(LuckPermsPlugin plugin) {
this.plugin = plugin;
@ -190,7 +190,7 @@ public abstract class AbstractCachedData implements CachedData {
Objects.requireNonNull(contexts, "contexts");
//noinspection ConstantConditions
return this.permission.get(contexts);
return this.permission.get(contexts).join();
}
@Nonnull
@ -199,7 +199,7 @@ public abstract class AbstractCachedData implements CachedData {
Objects.requireNonNull(contexts, "contexts");
//noinspection ConstantConditions
return this.meta.get(contexts);
return this.meta.get(contexts).join();
}
@Nonnull
@ -233,13 +233,13 @@ public abstract class AbstractCachedData implements CachedData {
@Override
public void recalculatePermissions(@Nonnull Contexts contexts) {
Objects.requireNonNull(contexts, "contexts");
this.permission.refresh(contexts);
this.permission.synchronous().refresh(contexts);
}
@Override
public void recalculateMeta(@Nonnull MetaContexts contexts) {
Objects.requireNonNull(contexts, "contexts");
this.meta.refresh(contexts);
this.meta.synchronous().refresh(contexts);
}
@Override
@ -254,13 +254,19 @@ public abstract class AbstractCachedData implements CachedData {
Objects.requireNonNull(contexts, "contexts");
// get the previous value - to use when recalculating
PermissionCache previous = this.permission.getIfPresent(contexts);
CompletableFuture<PermissionCache> previous = this.permission.getIfPresent(contexts);
// invalidate the entry
this.permission.invalidate(contexts);
// invalidate any previous setting
this.permission.synchronous().invalidate(contexts);
// repopulate the cache
return CompletableFuture.supplyAsync(() -> this.permission.get(contexts, c -> calculatePermissions(c, previous)));
// if the previous value is already calculated, use it when recalculating.
PermissionCache value = getIfReady(previous);
if (value != null) {
return this.permission.get(contexts, c -> calculatePermissions(c, value));
}
// otherwise, just calculate a new value
return this.permission.get(contexts);
}
@Nonnull
@ -269,13 +275,19 @@ public abstract class AbstractCachedData implements CachedData {
Objects.requireNonNull(contexts, "contexts");
// get the previous value - to use when recalculating
MetaCache previous = this.meta.getIfPresent(contexts);
CompletableFuture<MetaCache> previous = this.meta.getIfPresent(contexts);
// invalidate the entry
this.meta.invalidate(contexts);
// invalidate any previous setting
this.meta.synchronous().invalidate(contexts);
// repopulate the cache
return CompletableFuture.supplyAsync(() -> this.meta.get(contexts, c -> calculateMeta(c, previous)));
// if the previous value is already calculated, use it when recalculating.
MetaCache value = getIfReady(previous);
if (value != null) {
return this.meta.get(contexts, c -> calculateMeta(c, value));
}
// otherwise, just calculate a new value
return this.meta.get(contexts);
}
@Nonnull
@ -287,30 +299,34 @@ public abstract class AbstractCachedData implements CachedData {
@Override
public void recalculatePermissions() {
Set<Contexts> keys = this.permission.asMap().keySet();
Set<Contexts> keys = this.permission.synchronous().asMap().keySet();
keys.forEach(this::recalculatePermissions);
}
@Override
public void recalculateMeta() {
Set<MetaContexts> keys = this.meta.asMap().keySet();
Set<MetaContexts> keys = this.meta.synchronous().asMap().keySet();
keys.forEach(this::recalculateMeta);
}
@Nonnull
@Override
public CompletableFuture<Void> reloadPermissions() {
Set<Contexts> keys = new HashSet<>(this.permission.asMap().keySet());
Set<Contexts> keys = this.permission.synchronous().asMap().keySet();
return CompletableFuture.allOf(keys.stream().map(this::reloadPermissions).toArray(CompletableFuture[]::new));
}
@Nonnull
@Override
public CompletableFuture<Void> reloadMeta() {
Set<MetaContexts> keys = new HashSet<>(this.meta.asMap().keySet());
Set<MetaContexts> keys = this.meta.synchronous().asMap().keySet();
return CompletableFuture.allOf(keys.stream().map(this::reloadMeta).toArray(CompletableFuture[]::new));
}
public CompletableFuture<Void> reloadAll() {
return CompletableFuture.allOf(reloadPermissions(), reloadMeta());
}
@Override
public void preCalculate(@Nonnull Contexts contexts) {
Objects.requireNonNull(contexts, "contexts");
@ -324,34 +340,45 @@ public abstract class AbstractCachedData implements CachedData {
@Override
public void invalidatePermissions(@Nonnull Contexts contexts) {
Objects.requireNonNull(contexts, "contexts");
this.permission.invalidate(contexts);
this.permission.synchronous().invalidate(contexts);
}
@Override
public void invalidateMeta(@Nonnull MetaContexts contexts) {
Objects.requireNonNull(contexts, "contexts");
this.meta.invalidate(contexts);
this.meta.synchronous().invalidate(contexts);
}
@Override
public void invalidateMeta(@Nonnull Contexts contexts) {
Objects.requireNonNull(contexts, "contexts");
this.meta.invalidate(getDefaultMetaContexts(contexts));
this.meta.synchronous().invalidate(getDefaultMetaContexts(contexts));
}
@Override
public void invalidatePermissionCalculators() {
this.permission.asMap().values().forEach(PermissionCache::invalidateCache);
this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache);
}
public void invalidateCaches() {
this.permission.invalidateAll();
this.meta.invalidateAll();
this.permission.synchronous().invalidateAll();
this.meta.synchronous().invalidateAll();
}
public void doCacheCleanup() {
this.permission.cleanUp();
this.meta.cleanUp();
this.permission.synchronous().cleanUp();
this.meta.synchronous().cleanUp();
}
private static boolean isReady(@Nullable CompletableFuture<?> future) {
return (future != null) && future.isDone()
&& !future.isCompletedExceptionally()
&& (future.join() != null);
}
/** Returns the current value or null if either not done or failed. */
private static <V> V getIfReady(@Nullable CompletableFuture<V> future) {
return isReady(future) ? future.join() : null;
}
private final class PermissionCacheLoader implements CacheLoader<Contexts, PermissionCache> {

View File

@ -108,7 +108,7 @@ public final class StorageAssistant {
return;
}
user.getRefreshBuffer().requestDirectly();
user.reloadCachedData().join();
Optional<InternalMessagingService> messagingService = plugin.getMessagingService();
if (messagingService.isPresent() && plugin.getConfiguration().get(ConfigKeys.AUTO_PUSH_UPDATES)) {

View File

@ -36,8 +36,6 @@ public interface ConfigurationAdapter {
void reload();
boolean contains(String path);
String getString(String path, String def);
int getInt(String path, int def);

View File

@ -29,7 +29,6 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.common.api.delegates.model.ApiGroup;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.buffers.Cache;
import me.lucko.luckperms.common.caching.GroupCachedData;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -61,34 +60,66 @@ public class Group extends PermissionHolder implements Identifiable<String> {
*/
private final GroupCachedData cachedData;
/**
* The group's cached data refresh buffer
*/
private final GroupRefreshBuffer refreshBuffer;
public Group(String name, LuckPermsPlugin plugin) {
super(name, plugin);
super(plugin);
this.name = name.toLowerCase();
this.refreshBuffer = new GroupRefreshBuffer(plugin, this);
this.cachedData = new GroupCachedData(this);
getPlugin().getEventFactory().handleGroupCacheLoad(this, this.cachedData);
// invalidate our caches when data is updated
getStateListeners().add(this.refreshBuffer::request);
}
@Override
protected void invalidateCache() {
super.invalidateCache();
// invalidate our caches
this.weightCache.invalidate();
this.displayNameCache.invalidate();
super.invalidateCache();
}
// name getters
public String getName() {
return this.name;
}
@Override
public String getObjectName() {
return this.name;
}
@Override
public String getId() {
return this.name;
}
@Override
public String getFriendlyName() {
Optional<String> dn = getDisplayName();
return dn.map(s -> this.name + " (" + s + ")").orElse(this.name);
}
public Optional<String> getDisplayName() {
return this.displayNameCache.get();
}
/**
* Gets a display name value exactly matching a specific context.
*
* <p>Note that the behaviour of {@link #getDisplayName()} is not the same as this.</p>
*
* @param contextSet the contexts to lookup in
* @return the display name
*/
public Optional<String> getDisplayName(ContextSet contextSet) {
for (Node n : getData(NodeMapType.ENDURING).immutable().get(contextSet.makeImmutable())) {
Optional<DisplayNameType> displayName = n.getTypeData(DisplayNameType.KEY);
if (displayName.isPresent()) {
return Optional.of(displayName.get().getDisplayName());
}
}
return Optional.empty();
}
public ApiGroup getApiDelegate() {
return this.apiDelegate;
}
@ -98,36 +129,6 @@ public class Group extends PermissionHolder implements Identifiable<String> {
return this.cachedData;
}
@Override
public BufferedRequest<Void> getRefreshBuffer() {
return this.refreshBuffer;
}
@Override
public String getId() {
return this.name;
}
public Optional<String> getDisplayName() {
return this.displayNameCache.get();
}
public Optional<String> getDisplayName(ContextSet contextSet) {
for (Node n : getData(NodeMapType.ENDURING).immutable().get(contextSet.makeImmutable())) {
Optional<DisplayNameType> displayName = n.getTypeData(DisplayNameType.KEY);
if (displayName.isPresent()) {
return Optional.of(displayName.get().getDisplayName());
}
}
return Optional.empty();
}
@Override
public String getFriendlyName() {
Optional<String> dn = getDisplayName();
return dn.map(s -> this.name + " (" + s + ")").orElse(this.name);
}
@Override
public OptionalInt getWeight() {
return this.weightCache.get();
@ -138,11 +139,10 @@ public class Group extends PermissionHolder implements Identifiable<String> {
return HolderType.GROUP;
}
private CompletableFuture<Void> reloadCachedData() {
return CompletableFuture.allOf(
this.cachedData.reloadPermissions(),
this.cachedData.reloadMeta()
).thenAccept(n -> getPlugin().getEventFactory().handleGroupDataRecalculate(this, this.cachedData));
@Override
public CompletableFuture<Void> reloadCachedData() {
return this.cachedData.reloadAll()
.thenAccept(n -> getPlugin().getEventFactory().handleGroupDataRecalculate(this, this.cachedData));
}
@Override
@ -163,18 +163,4 @@ public class Group extends PermissionHolder implements Identifiable<String> {
return "Group(name=" + this.name + ")";
}
private static final class GroupRefreshBuffer extends BufferedRequest<Void> {
private final Group group;
private GroupRefreshBuffer(LuckPermsPlugin plugin, Group group) {
super(50L, 5L, plugin.getBootstrap().getScheduler().async());
this.group = group;
}
@Override
protected Void perform() {
return this.group.reloadCachedData().join();
}
}
}

View File

@ -40,9 +40,7 @@ import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.caching.HolderCachedData;
import me.lucko.luckperms.common.caching.handlers.StateListener;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.inheritance.InheritanceComparator;
@ -67,7 +65,7 @@ import java.util.OptionalInt;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
@ -95,18 +93,6 @@ import java.util.function.Predicate;
*/
public abstract class PermissionHolder {
/**
* The name of this object.
*
* <p>Used as a base for identifying permission holding objects. Also acts
* as a method for preventing circular inheritance issues.</p>
*
* @see User#getUuid()
* @see Group#getName()
* @see #getObjectName()
*/
private final String objectName;
/**
* Reference to the main plugin instance
* @see #getPlugin()
@ -146,18 +132,15 @@ public abstract class PermissionHolder {
private final Comparator<Group> inheritanceComparator = InheritanceComparator.getFor(this);
/**
* A set of runnables which are called when this objects state changes.
* Creates a new instance
*
* @param plugin the plugin instance
*/
private final Set<StateListener> stateListeners = ConcurrentHashMap.newKeySet();
protected PermissionHolder(String objectName, LuckPermsPlugin plugin) {
this.objectName = objectName;
protected PermissionHolder(LuckPermsPlugin plugin) {
this.plugin = plugin;
}
public String getObjectName() {
return this.objectName;
}
// getters
public LuckPermsPlugin getPlugin() {
return this.plugin;
@ -167,52 +150,6 @@ public abstract class PermissionHolder {
return this.ioLock;
}
public Set<StateListener> getStateListeners() {
return this.stateListeners;
}
protected void invalidateCache() {
this.enduringNodes.invalidate();
this.transientNodes.invalidate();
// Invalidate listeners
for (StateListener listener : this.stateListeners) {
try {
listener.onStateChange();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Gets the friendly name of this permission holder (for use in commands, etc)
*
* @return the holders "friendly" name
*/
public abstract String getFriendlyName();
/**
* Gets the holders cached data
*
* @return the holders cached data
*/
public abstract HolderCachedData<?> getCachedData();
/**
* Gets the holders refresh buffer
*
* @return the holders refresh buffer
*/
public abstract BufferedRequest<Void> getRefreshBuffer();
/**
* Returns the type of this PermissionHolder.
*
* @return this holders type
*/
public abstract HolderType getType();
public Comparator<Group> getInheritanceComparator() {
return this.inheritanceComparator;
}
@ -236,6 +173,51 @@ public abstract class PermissionHolder {
return this.transientNodes;
}
/**
* Gets the unique name of this holder object.
*
* <p>Used as a base for identifying permission holding objects. Also acts
* as a method for preventing circular inheritance issues.</p>
*
* @return the object name
*/
public abstract String getObjectName();
/**
* Gets the friendly name of this permission holder (for use in commands, etc)
*
* @return the holders "friendly" name
*/
public abstract String getFriendlyName();
/**
* Gets the holders cached data
*
* @return the holders cached data
*/
public abstract HolderCachedData<?> getCachedData();
/**
* Returns the type of this PermissionHolder.
*
* @return this holders type
*/
public abstract HolderType getType();
/**
* Reloads the holder's cached data.
*
* @return a future encapsulating the result
*/
public abstract CompletableFuture<Void> reloadCachedData();
protected void invalidateCache() {
this.enduringNodes.invalidate();
this.transientNodes.invalidate();
reloadCachedData();
}
public void setNodes(NodeMapType type, Set<Node> set) {
getData(type).setContent(set);
invalidateCache();

View File

@ -26,16 +26,18 @@
package me.lucko.luckperms.common.model;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.caching.UserCachedData;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.primarygroup.CachedPrimaryGroupHolder;
import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
public class User extends PermissionHolder implements Identifiable<UserIdentifier> {
/**
@ -46,6 +48,7 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
/**
* The last known username of a player
*/
@Nullable
private String name = null;
/**
@ -58,14 +61,11 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
*/
private final UserCachedData cachedData;
private final UserRefreshBuffer refreshBuffer;
public User(UUID uuid, String name, LuckPermsPlugin plugin) {
super(uuid.toString(), plugin);
super(plugin);
this.uuid = uuid;
setName(name, false);
this.refreshBuffer = new UserRefreshBuffer(plugin, this);
this.primaryGroup = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION).apply(this);
this.cachedData = new UserCachedData(this);
@ -76,22 +76,27 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
this(uuid, null, plugin);
}
@Override
protected void invalidateCache() {
super.invalidateCache();
// invalidate our caches
if (this.primaryGroup instanceof CachedPrimaryGroupHolder) {
((CachedPrimaryGroupHolder) this.primaryGroup).invalidate();
}
}
public UUID getUuid() {
return this.uuid;
}
public PrimaryGroupHolder getPrimaryGroup() {
return this.primaryGroup;
public Optional<String> getName() {
return Optional.ofNullable(this.name);
}
@Override
public UserCachedData getCachedData() {
return this.cachedData;
}
@Override
public BufferedRequest<Void> getRefreshBuffer() {
return this.refreshBuffer;
public String getObjectName() {
return this.uuid.toString();
}
@Override
@ -99,8 +104,18 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
return UserIdentifier.of(this.uuid, this.name);
}
public Optional<String> getName() {
return Optional.ofNullable(this.name);
@Override
public String getFriendlyName() {
return this.name != null ? this.name : this.uuid.toString();
}
@Override
public UserCachedData getCachedData() {
return this.cachedData;
}
public PrimaryGroupHolder getPrimaryGroup() {
return this.primaryGroup;
}
/**
@ -152,11 +167,6 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
}
}
@Override
public String getFriendlyName() {
return this.name != null ? this.name : this.uuid.toString();
}
@Override
public HolderType getType() {
return HolderType.USER;
@ -168,7 +178,7 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
*/
public void preCalculateData() {
// first try to refresh any existing permissions
this.refreshBuffer.requestDirectly();
reloadCachedData().join();
// pre-calc the allowall & global contexts
// since contexts change so frequently, it's not worth trying to calculate any more than this.
@ -176,11 +186,10 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
this.cachedData.preCalculate(Contexts.global());
}
@Override
public CompletableFuture<Void> reloadCachedData() {
return CompletableFuture.allOf(
this.cachedData.reloadPermissions(),
this.cachedData.reloadMeta()
).thenAccept(n -> getPlugin().getEventFactory().handleUserDataRecalculate(this, this.cachedData));
return this.cachedData.reloadAll()
.thenAccept(n -> getPlugin().getEventFactory().handleUserDataRecalculate(this, this.cachedData));
}
/**
@ -197,13 +206,6 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
return true;
}
public void clearNodes(boolean giveDefault) {
super.clearNodes();
if (giveDefault) {
getPlugin().getUserManager().giveDefaultIfNeeded(this, false);
}
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
@ -222,18 +224,4 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
return "User(uuid=" + this.uuid + ")";
}
private static final class UserRefreshBuffer extends BufferedRequest<Void> {
private final User user;
private UserRefreshBuffer(LuckPermsPlugin plugin, User user) {
super(50L, 5L, plugin.getBootstrap().getScheduler().async());
this.user = user;
}
@Override
protected Void perform() {
return this.user.reloadCachedData().join();
}
}
}

View File

@ -26,16 +26,15 @@
package me.lucko.luckperms.common.primarygroup;
import me.lucko.luckperms.common.buffers.Cache;
import me.lucko.luckperms.common.caching.handlers.StateListener;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import javax.annotation.Nonnull;
/**
* Abstract implementation of {@link StateListener} which caches all lookups.
* Abstract implementation of {@link PrimaryGroupHolder} which caches all lookups.
*/
public abstract class CachedPrimaryGroupHolder extends StoredHolder implements StateListener {
public abstract class CachedPrimaryGroupHolder extends StoredHolder {
// cache lookups
private final Cache<String> cache = new Cache<String>() {
@ -48,20 +47,18 @@ public abstract class CachedPrimaryGroupHolder extends StoredHolder implements S
public CachedPrimaryGroupHolder(User user) {
super(user);
user.getStateListeners().add(this);
}
protected abstract String calculateValue();
public void invalidate() {
this.cache.invalidate();;
}
@Override
public final String getValue() {
String s = this.cache.get();
return s != null ? s : getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME);
}
@Override
public void onStateChange() {
this.cache.invalidate();
}
}

View File

@ -205,7 +205,7 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
} finally {
user.getIoLock().unlock();
}
user.getRefreshBuffer().requestDirectly();
user.reloadCachedData().join();
return user;
}
@ -261,7 +261,7 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
} finally {
group.getIoLock().unlock();
}
group.getRefreshBuffer().requestDirectly();
group.reloadCachedData().join();
return group;
}
@ -295,7 +295,7 @@ public abstract class AbstractConfigurateDao extends AbstractDao {
group.getIoLock().unlock();
}
}
group.getRefreshBuffer().requestDirectly();
group.reloadCachedData().join();
return Optional.of(group);
}

View File

@ -286,7 +286,7 @@ public class MongoDao extends AbstractDao {
} finally {
user.getIoLock().unlock();
}
user.getRefreshBuffer().requestDirectly();
user.reloadCachedData().join();
return user;
}
@ -357,7 +357,7 @@ public class MongoDao extends AbstractDao {
} finally {
group.getIoLock().unlock();
}
group.getRefreshBuffer().requestDirectly();
group.reloadCachedData().join();
return group;
}
@ -388,7 +388,7 @@ public class MongoDao extends AbstractDao {
group.getIoLock().unlock();
}
}
group.getRefreshBuffer().requestDirectly();
group.reloadCachedData().join();
return Optional.of(group);
}

View File

@ -356,7 +356,7 @@ public class SqlDao extends AbstractDao {
} finally {
user.getIoLock().unlock();
}
user.getRefreshBuffer().requestDirectly();
user.reloadCachedData().join();
return user;
}
@ -595,7 +595,7 @@ public class SqlDao extends AbstractDao {
} finally {
group.getIoLock().unlock();
}
group.getRefreshBuffer().requestDirectly();
group.reloadCachedData().join();
return Optional.of(group);
}

View File

@ -57,7 +57,7 @@ public class ExpireTemporaryTask implements Runnable {
if (user.auditTemporaryPermissions()) {
this.plugin.getStorage().saveUser(user);
if (!groupChanges) {
user.getRefreshBuffer().request();
user.reloadCachedData();
}
}
}

View File

@ -55,11 +55,6 @@ public class NukkitConfigAdapter extends AbstractConfigurationAdapter implements
this.configuration = new Config(this.file, Config.YAML);
}
@Override
public boolean contains(String path) {
return this.configuration.exists(path);
}
@Override
public String getString(String path, String def) {
return this.configuration.getString(path, def);

View File

@ -85,11 +85,6 @@ public class SpongeConfigAdapter extends AbstractConfigurationAdapter implements
return node;
}
@Override
public boolean contains(String path) {
return !resolvePath(path).isVirtual();
}
@Override
public String getString(String path, String def) {
return resolvePath(path).getString(def);

View File

@ -37,6 +37,13 @@ public class SpongeGroup extends Group implements SpongePermissionHolder {
this.spongeData = new GroupSubject(plugin, this);
}
@Override
protected void invalidateCache() {
super.invalidateCache();
this.spongeData.fireUpdateEvent();
}
@Override
public GroupSubject sponge() {
return this.spongeData;

View File

@ -48,6 +48,13 @@ public class SpongeUser extends User implements SpongePermissionHolder {
this.spongeData = new UserSubject(plugin, this);
}
@Override
protected void invalidateCache() {
super.invalidateCache();
this.spongeData.fireUpdateEvent();
}
@Override
public UserSubject sponge() {
return this.spongeData;

View File

@ -66,12 +66,11 @@ public abstract class HolderSubject<T extends PermissionHolder> implements LPSub
this.plugin = plugin;
this.subjectData = new HolderSubjectData(plugin.getService(), NodeMapType.ENDURING, parent, this);
this.transientSubjectData = new HolderSubjectData(plugin.getService(), NodeMapType.TRANSIENT, parent, this);
}
// fire update event
parent.getStateListeners().add(() -> {
plugin.getUpdateEventHandler().fireUpdateEvent(this.subjectData);
plugin.getUpdateEventHandler().fireUpdateEvent(this.transientSubjectData);
});
public void fireUpdateEvent() {
this.plugin.getUpdateEventHandler().fireUpdateEvent(this.subjectData);
this.plugin.getUpdateEventHandler().fireUpdateEvent(this.transientSubjectData);
}
public T getParent() {

View File

@ -450,7 +450,7 @@ public class HolderSubjectData implements LPSubjectData {
// don't bother saving to primary storage. just refresh
if (t.getType().isUser()) {
User user = ((User) t);
return user.getRefreshBuffer().request();
return user.reloadCachedData();
} else {
return this.service.getPlugin().getUpdateTaskBuffer().request();
}
@ -465,7 +465,7 @@ public class HolderSubjectData implements LPSubjectData {
fut.complete(null);
}
user.getRefreshBuffer().request().thenAccept(fut::complete);
user.reloadCachedData().thenAccept(fut::complete);
}, this.service.getPlugin().getBootstrap().getScheduler().async());
return fut;
} else {