Remove context pre-processing (mostly)

This approach isn't very effective when contexts are frequently changing, and it is hard to guess in advance which contexts are going to be in-use.

The Sponge version has proven that this whole system isn't really necessary.

Contexts for 'allow all' and 'global' are still pre-processed, however this should be significantly less work for the server. (even if it is being done async)
This commit is contained in:
Luck 2017-10-12 20:17:52 +01:00
parent 9c505e4402
commit 8920396360
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
15 changed files with 53 additions and 227 deletions

View File

@ -174,11 +174,6 @@ public class BukkitListener implements Listener {
}
plugin.refreshAutoOp(player);
// We assume all users are not op, but those who are need extra calculation.
if (player.isOp()) {
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
}
}
@EventHandler(priority = EventPriority.MONITOR)

View File

@ -31,8 +31,6 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.calculators.BukkitCalculatorFactory;
import me.lucko.luckperms.bukkit.contexts.BukkitContextManager;
import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
@ -82,7 +80,6 @@ import me.lucko.luckperms.common.utils.LoginHelper;
import me.lucko.luckperms.common.utils.UuidCache;
import me.lucko.luckperms.common.verbose.VerboseHandler;
import org.bukkit.World;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
@ -346,7 +343,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
final User user = getUserManager().getIfLoaded(getUuidCache().getUUID(player.getUniqueId()));
if (user != null) {
user.unregisterData();
user.getUserData().invalidateCaches();
getUserManager().unload(user);
}
}
@ -376,31 +373,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// Bukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere.
getServer().getScheduler().cancelTasks(this);
HandlerList.unregisterAll(this);
// Null everything
vaultHookManager = null;
configuration = null;
userManager = null;
groupManager = null;
trackManager = null;
storage = null;
fileWatcher = null;
messagingService = null;
uuidCache = null;
listener = null;
apiProvider = null;
log = null;
defaultsProvider = null;
childPermissionProvider = null;
localeManager = null;
cachedStateManager = null;
contextManager = null;
calculatorFactory = null;
updateTaskBuffer = null;
verboseHandler = null;
senderFactory = null;
permissionVault = null;
logDispatcher = null;
getLog().info("Goodbye!");
}
public void tryVaultHook(boolean force) {
@ -538,75 +511,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
// Pre process all worlds
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
set.add("world", s);
set.addAll(configuration.getContextsFile().getStaticContexts());
return set.makeImmutable();
})
.collect(Collectors.toList())
);
// Pre process the separate Vault server, if any
if (!getConfiguration().get(ConfigKeys.SERVER).equals(getConfiguration().get(ConfigKeys.VAULT_SERVER))) {
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.VAULT_SERVER)));
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", getConfiguration().get(ConfigKeys.VAULT_SERVER));
set.add("world", s);
set.addAll(configuration.getContextsFile().getStaticContexts());
return set.makeImmutable();
})
.collect(Collectors.toList())
);
}
Set<Contexts> contexts = new HashSet<>();
// Convert to full Contexts
contexts.addAll(c.stream()
.map(set -> new Contexts(
set,
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
op
))
.collect(Collectors.toSet())
);
// Check for and include varying Vault config options
boolean vaultDiff = getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL) != getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS) ||
!getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS) ||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS) ||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS);
if (vaultDiff) {
contexts.addAll(c.stream()
.map(map -> new Contexts(map, getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL), true, true, true, true, op))
.collect(Collectors.toSet())
);
}
return contexts;
}
@Override
public LinkedHashMap<String, Object> getExtraInfo() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
public Map<String, Object> getExtraInfo() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("Vault Enabled", vaultHookManager != null);
map.put("Bukkit Defaults count", defaultsProvider.size());
map.put("Bukkit Child Permissions count", childPermissionProvider.getPermissions().size());

View File

@ -29,7 +29,6 @@ import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
@ -44,12 +43,10 @@ import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PermissionCheckEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RequiredArgsConstructor
@ -192,24 +189,4 @@ public class BungeeListener implements Listener {
e.setResult(result);
}
// We don't pre-process all servers, so we have to do it here.
@EventHandler(priority = EventPriority.LOWEST)
public void onServerSwitch(ServerConnectEvent e) {
String serverName = e.getTarget().getName();
UUID uuid = e.getPlayer().getUniqueId();
plugin.doAsync(() -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", plugin.getConfiguration().get(ConfigKeys.SERVER));
set.add("world", serverName);
User user = plugin.getUserManager().getIfLoaded(plugin.getUuidCache().getUUID(uuid));
if (user == null) {
return;
}
Contexts contexts = plugin.getContextManager().formContexts(e.getPlayer(), set.makeImmutable());
user.getUserData().preCalculate(contexts);
});
}
}

View File

@ -30,8 +30,6 @@ import lombok.Getter;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.bungee.calculators.BungeeCalculatorFactory;
import me.lucko.luckperms.bungee.contexts.BackendServerCalculator;
import me.lucko.luckperms.bungee.contexts.BungeeContextManager;
@ -83,7 +81,6 @@ import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -215,6 +212,9 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
@Override
public void onDisable() {
permissionVault.setShutdown(true);
verboseHandler.setShutdown(true);
getLog().info("Closing storage...");
storage.shutdown();
@ -231,8 +231,10 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
getLog().info("Shutting down internal scheduler...");
scheduler.shutdown();
getProxy().getScheduler().cancel(this);
getProxy().getPluginManager().unregisterListeners(this);
getLog().info("Goodbye!");
}
@Override
@ -324,14 +326,4 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
public Sender getConsoleSender() {
return getSenderFactory().wrap(getProxy().getConsole());
}
@Override
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ImmutableContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
return c.stream()
.map(set -> contextManager.formContexts(null, set))
.collect(Collectors.toSet());
}
}

View File

@ -108,7 +108,7 @@ public final class UserDelegate extends PermissionHolderDelegate implements User
@Override
public void setupDataCache() {
handle.preCalculateData(false);
handle.preCalculateData();
}
@Override

View File

@ -31,12 +31,10 @@ import lombok.RequiredArgsConstructor;
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 me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.contexts.ExtractedContexts;
@ -59,20 +57,22 @@ public class UserCache implements UserData {
private final User user;
private final LoadingCache<Contexts, PermissionCache> permission = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.expireAfterAccess(2, TimeUnit.MINUTES)
.build(new PermissionCacheLoader());
private final LoadingCache<MetaContexts, MetaCache> meta = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.expireAfterAccess(2, TimeUnit.MINUTES)
.build(new MetaCacheLoader());
@Override
public PermissionCache getPermissionData(@NonNull Contexts contexts) {
//noinspection ConstantConditions
return permission.get(contexts);
}
@Override
public MetaCache getMetaData(@NonNull MetaContexts contexts) {
//noinspection ConstantConditions
return meta.get(contexts);
}
@ -131,14 +131,14 @@ public class UserCache implements UserData {
@Override
public void recalculatePermissions() {
Set<Contexts> keys = ImmutableSet.copyOf(permission.asMap().keySet());
keys.forEach(permission::refresh);
Set<Contexts> keys = permission.asMap().keySet();
keys.forEach(this::recalculatePermissions);
}
@Override
public void recalculateMeta() {
Set<MetaContexts> keys = ImmutableSet.copyOf(meta.asMap().keySet());
keys.forEach(meta::refresh);
Set<MetaContexts> keys = meta.asMap().keySet();
keys.forEach(this::recalculateMeta);
}
@Override
@ -148,30 +148,27 @@ public class UserCache implements UserData {
@Override
public void preCalculate(@NonNull Contexts contexts) {
permission.get(contexts);
meta.get(makeFromMetaContextsConfig(contexts, user.getPlugin()));
// pre-calculate just by requesting the data from this cache.
// if the data isn't already loaded, it will be calculated.
getPermissionData(contexts);
getMetaData(contexts);
}
public void invalidateCache() {
public void invalidateCaches() {
permission.invalidateAll();
meta.invalidateAll();
}
@Override
public void invalidatePermissionCalculators() {
permission.asMap().values().forEach(PermissionData::invalidateCache);
permission.asMap().values().forEach(PermissionCache::invalidateCache);
}
public void cleanup() {
public void doCacheCleanup() {
permission.cleanUp();
meta.cleanUp();
}
public void clear() {
permission.invalidateAll();
meta.invalidateAll();
}
private final class PermissionCacheLoader implements CacheLoader<Contexts, PermissionCache> {
@Override
public PermissionCache load(Contexts contexts) {

View File

@ -99,7 +99,7 @@ public class GenericUserManager extends AbstractManager<UserIdentifier, User> im
plugin.getScheduler().asyncLater(() -> {
User user = getIfLoaded(plugin.getUuidCache().getUUID(uuid));
if (user != null && !plugin.isPlayerOnline(uuid)) {
user.unregisterData();
user.getUserData().invalidateCaches();
unload(user);
plugin.getUuidCache().clearCache(uuid);
}

View File

@ -29,6 +29,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.api.delegates.UserDelegate;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.caching.UserCache;
@ -161,16 +162,14 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
* Sets up the UserData cache
* Blocking call.
*/
public synchronized void preCalculateData(boolean op) {
userData.preCalculate(getPlugin().getPreProcessContexts(op));
getPlugin().onUserRefresh(this);
}
public synchronized void preCalculateData() {
// first try to refresh any existing permissions
refreshPermissions();
/**
* Removes the UserData cache from this user
*/
public void unregisterData() {
userData.clear();
// pre-calc the allowall & global contexts
// since contexts change so frequently, it's not worth trying to calculate any more than this.
userData.preCalculate(Contexts.allowAll());
userData.preCalculate(Contexts.global());
}
/**
@ -205,10 +204,6 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
}
}
public void cleanup() {
userData.cleanup();
}
private static final class UserRefreshBuffer extends BufferedRequest<Void> {
private final User user;

View File

@ -55,8 +55,8 @@ import me.lucko.luckperms.common.verbose.VerboseHandler;
import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@ -369,14 +369,6 @@ public interface LuckPermsPlugin {
*/
Set<UUID> getUniqueConnections();
/**
* Gets a set of Contexts that should be pre-processed in advance
*
* @param op if the user being processed is op
* @return a set of contexts
*/
Set<Contexts> getPreProcessContexts(boolean op);
default List<Command> getExtraCommands() {
return Collections.emptyList();
}
@ -386,7 +378,7 @@ public interface LuckPermsPlugin {
*
* @return a map of options, or null
*/
default LinkedHashMap<String, Object> getExtraInfo() {
default Map<String, Object> getExtraInfo() {
return null;
}

View File

@ -37,7 +37,7 @@ public class CacheHousekeepingTask implements Runnable {
@Override
public void run() {
for (User user : plugin.getUserManager().getAll().values()) {
user.cleanup();
user.getUserData().doCacheCleanup();
}
}
}

View File

@ -90,7 +90,8 @@ public class LoginHelper {
plugin.getStorage().noBuffer().saveUser(user).join();
}
user.preCalculateData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
// Does some minimum pre-calculations to (maybe) speed things up later.
user.preCalculateData();
}
final long time = System.currentTimeMillis() - startTime;

View File

@ -114,6 +114,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@ -295,6 +296,9 @@ public class LPSpongePlugin implements LuckPermsPlugin {
@Listener
public void onDisable(GameStoppingServerEvent event) {
permissionVault.setShutdown(true);
verboseHandler.setShutdown(true);
getLog().info("Closing storage...");
storage.shutdown();
@ -311,6 +315,8 @@ public class LPSpongePlugin implements LuckPermsPlugin {
getLog().info("Shutting down internal scheduler...");
scheduler.shutdown();
getLog().info("Goodbye!");
}
@Listener
@ -470,19 +476,14 @@ public class LPSpongePlugin implements LuckPermsPlugin {
return getSenderFactory().wrap(game.getServer().getConsole());
}
@Override
public Set<Contexts> getPreProcessContexts(boolean op) {
return Collections.emptySet();
}
@Override
public List<Command> getExtraCommands() {
return Collections.singletonList(new SpongeMainCommand(this));
}
@Override
public LinkedHashMap<String, Object> getExtraInfo() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
public Map<String, Object> getExtraInfo() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("SubjectCollection count", service.getLoadedCollections().size());
map.put("Subject count",
service.getLoadedCollections().values().stream()

View File

@ -27,8 +27,6 @@ package me.lucko.luckperms.sponge;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.User;
@ -36,7 +34,6 @@ import me.lucko.luckperms.common.utils.LoginHelper;
import me.lucko.luckperms.common.utils.UuidCache;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.command.SendCommandEvent;
@ -45,15 +42,11 @@ import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.text.serializer.TextSerializers;
import org.spongepowered.api.util.Tristate;
import org.spongepowered.api.world.World;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class SpongeListener {
@ -160,29 +153,6 @@ public class SpongeListener {
e.setMessageCancelled(false);
//noinspection deprecation
e.setMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(Message.LOADING_ERROR.asString(plugin.getLocaleManager())));
return;
}
// Attempt to pre-process some permissions for the user to save time later. Might not work, but it's better than nothing.
Optional<Player> p = e.getCause().first(Player.class);
if (p.isPresent()) {
MutableContextSet context = MutableContextSet.fromSet(plugin.getContextManager().getApplicableContext(p.get()));
List<String> worlds = plugin.getGame().isServerAvailable() ? plugin.getGame().getServer().getWorlds().stream()
.map(World::getName)
.collect(Collectors.toList()) : Collections.emptyList();
plugin.doAsync(() -> {
UserData data = user.getUserData();
data.preCalculate(plugin.getService().calculateContexts(context.makeImmutable()));
for (String world : worlds) {
MutableContextSet modified = MutableContextSet.fromSet(context);
modified.removeAll("world");
modified.add("world", world);
data.preCalculate(plugin.getService().calculateContexts(modified.makeImmutable()));
}
});
}
}

View File

@ -85,7 +85,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
user.getIoLock().unlock();
// ok, data is here, let's do the pre-calculation stuff.
user.preCalculateData(false);
user.preCalculateData();
return user.sponge();
}
@ -97,7 +97,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
throw new RuntimeException();
}
user.preCalculateData(false);
user.preCalculateData();
return user.sponge();
});

View File

@ -191,7 +191,7 @@ public class SpongeUser extends User {
@Override
public void invalidateCaches(CacheLevel cacheLevel) {
// invalidate for all changes
parent.getUserData().invalidateCache();
parent.getUserData().invalidateCaches();
}
}