Optimize LookupSetting storage/manipulation within Contexts

Fixes some performance issues resulting from bad use / implementation of ImmutableEnumSets
This commit is contained in:
Luck 2018-11-23 23:58:49 +00:00
parent 2da6298c53
commit fe77834cef
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
3 changed files with 81 additions and 57 deletions

View File

@ -25,14 +25,11 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
@ -57,9 +54,9 @@ public class Contexts {
public static final String WORLD_KEY = "world";
/**
* The default {@link LookupSetting}s.
* The default {@link LookupSetting}s as a flag.
*/
private static final EnumSet<LookupSetting> DEFAULT_SETTINGS = EnumSet.of(
private static final byte DEFAULT_SETTINGS_FLAG = LookupSetting.createFlag(
LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER,
LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD,
LookupSetting.RESOLVE_INHERITANCE,
@ -73,7 +70,7 @@ public class Contexts {
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*/
private static final Contexts GLOBAL = new Contexts(ImmutableContextSet.empty(), ImmutableSet.copyOf(DEFAULT_SETTINGS));
private static final Contexts GLOBAL = new Contexts(ImmutableContextSet.empty(), DEFAULT_SETTINGS_FLAG);
/**
* Gets the {@link FullySatisfiedContexts} instance.
@ -111,7 +108,7 @@ public class Contexts {
*/
public static @NonNull Contexts of(@NonNull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
Objects.requireNonNull(contextSet, "contextSet");
EnumSet<LookupSetting> settings = formSettings(
byte settingsFlag = LookupSetting.createFlag(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
@ -119,18 +116,10 @@ public class Contexts {
applyParentsWithoutWorld,
isOp
);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settings)) {
if (contextSet.isEmpty() && DEFAULT_SETTINGS_FLAG == settingsFlag) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settings));
}
private static EnumSet<LookupSetting> asEnumSet(Set<LookupSetting> settings) {
if (settings instanceof EnumSet<?>) {
return ((EnumSet<LookupSetting>) settings);
} else {
return EnumSet.copyOf(settings);
}
return new Contexts(contextSet.makeImmutable(), settingsFlag);
}
/**
@ -144,12 +133,12 @@ public class Contexts {
Objects.requireNonNull(contextSet, "contextSet");
Objects.requireNonNull(settings, "settings");
EnumSet<LookupSetting> settingsCopy = asEnumSet(settings);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settingsCopy)) {
byte settingsFlag = LookupSetting.createFlag(settings);
if (contextSet.isEmpty() && DEFAULT_SETTINGS_FLAG == settingsFlag) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settingsCopy));
return new Contexts(contextSet.makeImmutable(), settingsFlag);
}
/**
@ -160,7 +149,7 @@ public class Contexts {
/**
* The settings for this lookup
*/
private final ImmutableSet<LookupSetting> settings;
private final byte settingsFlag;
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
private final int hashCode;
@ -180,20 +169,20 @@ public class Contexts {
@Deprecated
public Contexts(@NonNull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
this.contextSet = Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
this.settings = ImmutableSet.copyOf(formSettings(
this.settingsFlag = LookupSetting.createFlag(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
));
);
this.hashCode = calculateHashCode();
}
protected Contexts(@NonNull ImmutableContextSet contextSet, @NonNull ImmutableSet<LookupSetting> settings) {
protected Contexts(@NonNull ImmutableContextSet contextSet, byte settingsFlag) {
this.contextSet = contextSet;
this.settings = settings;
this.settingsFlag = settingsFlag;
this.hashCode = calculateHashCode();
}
@ -214,7 +203,7 @@ public class Contexts {
* @since 4.2
*/
public @NonNull Set<LookupSetting> getSettings() {
return this.settings;
return LookupSetting.createSetFromFlag(this.settingsFlag);
}
/**
@ -225,7 +214,7 @@ public class Contexts {
* @since 4.2
*/
public boolean hasSetting(@NonNull LookupSetting setting) {
return this.settings.contains(setting);
return LookupSetting.isSet(this.settingsFlag, setting);
}
/**
@ -302,7 +291,7 @@ public class Contexts {
@Override
public @NonNull String toString() {
return "Contexts(contextSet=" + this.contextSet + ", settings=" + this.settings + ")";
return "Contexts(contextSet=" + this.contextSet + ", settings=" + LookupSetting.createSetFromFlag(this.settingsFlag) + ")";
}
@Override
@ -311,14 +300,14 @@ public class Contexts {
if (o == allowAll()) return false;
if (!(o instanceof Contexts)) return false;
final Contexts that = (Contexts) o;
return this.contextSet.equals(that.contextSet) && this.settings.equals(that.settings);
return this.contextSet.equals(that.contextSet) && this.settingsFlag == that.settingsFlag;
}
private int calculateHashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.contextSet.hashCode();
result = result * PRIME + this.settings.hashCode();
result = result * PRIME + this.settingsFlag;
return result;
}
@ -327,27 +316,4 @@ public class Contexts {
return this.hashCode;
}
private static EnumSet<LookupSetting> formSettings(boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
EnumSet<LookupSetting> settings = EnumSet.noneOf(LookupSetting.class);
if (includeNodesSetWithoutServer) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
if (includeNodesSetWithoutWorld) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
if (resolveInheritance) {
settings.add(LookupSetting.RESOLVE_INHERITANCE);
}
if (applyParentsWithoutServer) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
if (applyParentsWithoutWorld) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
if (isOp) {
settings.add(LookupSetting.IS_OP);
}
return settings;
}
}

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.context.ImmutableContextSet;
@ -59,7 +57,7 @@ public final class FullySatisfiedContexts extends Contexts {
}
private FullySatisfiedContexts() {
super(ImmutableContextSet.empty(), ImmutableSet.copyOf(Contexts.global().getSettings()));
super(ImmutableContextSet.empty(), LookupSetting.createFlag(Contexts.global().getSettings()));
}
@Override

View File

@ -25,6 +25,9 @@
package me.lucko.luckperms.api;
import java.util.EnumSet;
import java.util.Set;
/**
* The various lookup setting flags for {@link Contexts}.
*
@ -60,5 +63,62 @@ public enum LookupSetting {
/**
* If global or non-world-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_WORLD
APPLY_PARENTS_SET_WITHOUT_WORLD;
/* bitwise utility methods */
static boolean isSet(byte b, LookupSetting setting) {
return ((b >> setting.ordinal()) & 1) == 1;
}
static byte createFlag(LookupSetting... settings) {
byte b = 0;
for (LookupSetting setting : settings) {
b |= (1 << setting.ordinal());
}
return b;
}
static byte createFlag(Set<LookupSetting> settings) {
byte b = 0;
for (LookupSetting setting : settings) {
b |= (1 << setting.ordinal());
}
return b;
}
static Set<LookupSetting> createSetFromFlag(byte b) {
EnumSet<LookupSetting> settings = EnumSet.noneOf(LookupSetting.class);
for (LookupSetting setting : LookupSetting.values()) {
if (((b >> setting.ordinal()) & 1) == 1) {
settings.add(setting);
}
}
return settings;
}
static byte createFlag(boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
byte b = 0;
if (includeNodesSetWithoutServer) {
b |= (1 << LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER.ordinal());
}
if (includeNodesSetWithoutWorld) {
b |= (1 << LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD.ordinal());
}
if (resolveInheritance) {
b |= (1 << LookupSetting.RESOLVE_INHERITANCE.ordinal());
}
if (applyParentsWithoutServer) {
b |= (1 << LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER.ordinal());
}
if (applyParentsWithoutWorld) {
b |= (1 << LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD.ordinal());
}
if (isOp) {
b |= (1 << LookupSetting.IS_OP.ordinal());
}
return b;
}
}