Rewrite the way user instances are cleaned up and unloaded - towards #674

This commit is contained in:
Luck
2018-01-10 21:28:33 +00:00
Unverified
parent ea94bd8696
commit 3201d10bdd
36 changed files with 725 additions and 468 deletions
@@ -52,8 +52,7 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.NoopLocaleManager;
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
import me.lucko.luckperms.common.logging.SenderLogger;
import me.lucko.luckperms.common.managers.GenericTrackManager;
import me.lucko.luckperms.common.managers.TrackManager;
import me.lucko.luckperms.common.managers.track.StandardTrackManager;
import me.lucko.luckperms.common.messaging.ExtendedMessagingService;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@@ -168,7 +167,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
private LuckPermsConfiguration configuration;
private SpongeUserManager userManager;
private SpongeGroupManager groupManager;
private TrackManager trackManager;
private StandardTrackManager trackManager;
private Storage storage;
private FileWatcher fileWatcher = null;
private ExtendedMessagingService messagingService = null;
@@ -243,7 +242,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
this.uuidCache = new UuidCache(this);
this.userManager = new SpongeUserManager(this);
this.groupManager = new SpongeGroupManager(this);
this.trackManager = new GenericTrackManager(this);
this.trackManager = new StandardTrackManager(this);
this.calculatorFactory = new SpongeCalculatorFactory(this);
this.cachedStateManager = new CachedStateManager();
@@ -561,7 +560,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
}
@Override
public TrackManager getTrackManager() {
public StandardTrackManager getTrackManager() {
return this.trackManager;
}
@@ -26,7 +26,10 @@
package me.lucko.luckperms.sponge;
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.SchedulerTask;
import me.lucko.luckperms.common.utils.SafeIterator;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.Task;
import java.util.Set;
@@ -35,12 +38,16 @@ import java.util.concurrent.Executor;
public class SpongeSchedulerAdapter implements SchedulerAdapter {
private final LPSpongePlugin plugin;
private final Set<Task> tasks = ConcurrentHashMap.newKeySet();
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
public SpongeSchedulerAdapter(LPSpongePlugin plugin) {
this.plugin = plugin;
}
private Scheduler scheduler() {
return this.plugin.getSpongeScheduler();
}
@Override
public Executor async() {
return this.plugin.getAsyncExecutorService();
@@ -62,29 +69,72 @@ public class SpongeSchedulerAdapter implements SchedulerAdapter {
}
@Override
public void asyncRepeating(Runnable runnable, long intervalTicks) {
Task task = this.plugin.getSpongeScheduler().createTaskBuilder().async().intervalTicks(intervalTicks).delayTicks(intervalTicks).execute(runnable).submit(this.plugin);
this.tasks.add(task);
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
Task task = scheduler().createTaskBuilder()
.async()
.intervalTicks(intervalTicks)
.delayTicks(intervalTicks)
.execute(runnable)
.submit(this.plugin);
SchedulerTask wrapped = new SpongeSchedulerTask(task);
this.tasks.add(wrapped);
return wrapped;
}
@Override
public void syncRepeating(Runnable runnable, long intervalTicks) {
Task task = this.plugin.getSpongeScheduler().createTaskBuilder().intervalTicks(intervalTicks).delayTicks(intervalTicks).execute(runnable).submit(this.plugin);
this.tasks.add(task);
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
Task task = scheduler().createTaskBuilder()
.intervalTicks(intervalTicks)
.delayTicks(intervalTicks)
.execute(runnable)
.submit(this.plugin);
SchedulerTask wrapped = new SpongeSchedulerTask(task);
this.tasks.add(wrapped);
return wrapped;
}
@Override
public void asyncLater(Runnable runnable, long delayTicks) {
this.plugin.getSpongeScheduler().createTaskBuilder().async().delayTicks(delayTicks).execute(runnable).submit(this.plugin);
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
Task task = scheduler().createTaskBuilder()
.async()
.delayTicks(delayTicks)
.execute(runnable)
.submit(this.plugin);
SchedulerTask wrapped = new SpongeSchedulerTask(task);
this.tasks.add(wrapped);
return wrapped;
}
@Override
public void syncLater(Runnable runnable, long delayTicks) {
this.plugin.getSpongeScheduler().createTaskBuilder().delayTicks(delayTicks).execute(runnable).submit(this.plugin);
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
Task task = scheduler().createTaskBuilder()
.delayTicks(delayTicks)
.execute(runnable)
.submit(this.plugin);
SchedulerTask wrapped = new SpongeSchedulerTask(task);
this.tasks.add(wrapped);
return wrapped;
}
@Override
public void shutdown() {
this.tasks.forEach(Task::cancel);
SafeIterator.iterate(this.tasks, SchedulerTask::cancel);
}
private static final class SpongeSchedulerTask implements SchedulerTask {
private final Task task;
private SpongeSchedulerTask(Task task) {
this.task = task;
}
@Override
public void cancel() {
this.task.cancel();
}
}
}
@@ -28,7 +28,7 @@ package me.lucko.luckperms.sponge.listeners;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.LoginHelper;
import me.lucko.luckperms.common.utils.AbstractLoginListener;
import me.lucko.luckperms.common.utils.UuidCache;
import me.lucko.luckperms.sponge.LPSpongePlugin;
@@ -45,13 +45,14 @@ import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class SpongeConnectionListener {
public class SpongeConnectionListener extends AbstractLoginListener {
private final LPSpongePlugin plugin;
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
private final Set<UUID> deniedLogin = Collections.synchronizedSet(new HashSet<>());
public SpongeConnectionListener(LPSpongePlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@@ -80,7 +81,7 @@ public class SpongeConnectionListener {
- creating a user instance in the UserManager for this connection.
- setting up cached data. */
try {
User user = LoginHelper.loadUser(this.plugin, p.getUniqueId(), username, false);
User user = loadUser(p.getUniqueId(), username);
this.plugin.getEventFactory().handleUserLoginProcess(p.getUniqueId(), username, user);
} catch (Exception ex) {
this.plugin.getLog().severe("Exception occured whilst loading data for " + p.getUniqueId() + " - " + p.getName());
@@ -165,6 +166,10 @@ public class SpongeConnectionListener {
// Unload the user from memory when they disconnect
cache.clearCache(e.getTargetEntity().getUniqueId());
// Register with the housekeeper, so the User's instance will stick
// around for a bit after they disconnect
this.plugin.getUserManager().getHouseKeeper().registerUsage(e.getTargetEntity().getUniqueId());
}
}
@@ -36,8 +36,7 @@ import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.managers.GroupManager;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.managers.group.AbstractGroupManager;
import me.lucko.luckperms.common.storage.DataConstraints;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.LPSpongePlugin;
@@ -61,15 +60,10 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
public class SpongeGroupManager extends AbstractGroupManager<SpongeGroup> implements LPSubjectCollection {
private final LPSpongePlugin plugin;
private SubjectCollection spongeProxy = null;
private final LoadingCache<String, SpongeGroup> objects = Caffeine.newBuilder()
.build(this::apply);
private final LoadingCache<String, LPSubject> subjectLoadingCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(s -> {
@@ -104,53 +98,6 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
return new SpongeGroup(name, this.plugin);
}
/* ------------------------------------------
* Manager methods
* ------------------------------------------ */
@Override
public Map<String, SpongeGroup> getAll() {
return ImmutableMap.copyOf(this.objects.asMap());
}
@Override
public SpongeGroup getOrMake(String id) {
return this.objects.get(id.toLowerCase());
}
@Override
public SpongeGroup getIfLoaded(String id) {
return this.objects.getIfPresent(id.toLowerCase());
}
@Override
public boolean isLoaded(String id) {
return this.objects.asMap().containsKey(id.toLowerCase());
}
@Override
public void unload(String id) {
if (id != null) {
this.objects.invalidate(id.toLowerCase());
}
}
@Override
public void unload(Group t) {
if (t != null) {
unload(t.getId());
}
}
@Override
public void unloadAll() {
this.objects.invalidateAll();
}
/* ------------------------------------------
* SubjectCollection methods
* ------------------------------------------ */
@Override
public synchronized SubjectCollection sponge() {
if (this.spongeProxy == null) {
@@ -160,6 +107,10 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
return this.spongeProxy;
}
public LPSpongePlugin getPlugin() {
return this.plugin;
}
@Override
public LuckPermsService getService() {
return this.plugin.getService();
@@ -261,7 +212,7 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
@Override
public ImmutableMap<LPSubject, Boolean> getLoadedWithPermission(String permission) {
return this.objects.asMap().values().stream()
return getAll().values().stream()
.map(SpongeGroup::sponge)
.map(sub -> Maps.immutableEntry(sub, sub.getPermissionValue(ImmutableContextSet.empty(), permission)))
.filter(pair -> pair.getValue() != Tristate.UNDEFINED)
@@ -270,7 +221,7 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
@Override
public ImmutableMap<LPSubject, Boolean> getLoadedWithPermission(ImmutableContextSet contexts, String permission) {
return this.objects.asMap().values().stream()
return getAll().values().stream()
.map(SpongeGroup::sponge)
.map(sub -> Maps.immutableEntry(sub, sub.getPermissionValue(contexts, permission)))
.filter(pair -> pair.getValue() != Tristate.UNDEFINED)
@@ -282,33 +233,4 @@ public class SpongeGroupManager implements GroupManager, LPSubjectCollection {
return getService().getDefaultSubjects().loadSubject(getIdentifier()).join();
}
@Override
public Group getByDisplayName(String name) {
// try to get an exact match first
Group g = getIfLoaded(name);
if (g != null) {
return g;
}
// then try exact display name matches
for (Group group : getAll().values()) {
if (group.getDisplayName().isPresent() && group.getDisplayName().get().equals(name)) {
return group;
}
}
// then try case insensitive name matches
for (Group group : getAll().values()) {
if (group.getDisplayName().isPresent() && group.getDisplayName().get().equalsIgnoreCase(name)) {
return group;
}
}
return null;
}
public LPSpongePlugin getPlugin() {
return this.plugin;
}
}
@@ -35,9 +35,8 @@ import com.google.common.collect.Maps;
import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.managers.GenericUserManager;
import me.lucko.luckperms.common.managers.UserManager;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.managers.user.AbstractUserManager;
import me.lucko.luckperms.common.managers.user.UserHousekeeper;
import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.sponge.LPSpongePlugin;
@@ -62,18 +61,16 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
public class SpongeUserManager implements UserManager, LPSubjectCollection {
public class SpongeUserManager extends AbstractUserManager<SpongeUser> implements LPSubjectCollection {
private final LPSpongePlugin plugin;
private SubjectCollection spongeProxy = null;
private final LoadingCache<UserIdentifier, SpongeUser> objects = Caffeine.newBuilder()
.build(this::apply);
private final LoadingCache<UUID, LPSubject> subjectLoadingCache = Caffeine.<UUID, LPSubject>newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(u -> {
// clock in with the housekeeper
getHouseKeeper().registerUsage(u);
// check if the user instance is already loaded.
SpongeUser user = getIfLoaded(u);
if (user != null) {
@@ -100,6 +97,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
});
public SpongeUserManager(LPSpongePlugin plugin) {
super(plugin, UserHousekeeper.timeoutSettings(10, TimeUnit.MINUTES));
this.plugin = plugin;
}
@@ -110,103 +108,6 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
new SpongeUser(id.getUuid(), id.getUsername().get(), this.plugin);
}
/* ------------------------------------------
* Manager methods
* ------------------------------------------ */
@Override
public Map<UserIdentifier, SpongeUser> getAll() {
return ImmutableMap.copyOf(this.objects.asMap());
}
@Override
public SpongeUser getOrMake(UserIdentifier id) {
SpongeUser ret = this.objects.get(id);
if (id.getUsername().isPresent()) {
ret.setName(id.getUsername().get(), false);
}
return ret;
}
@Override
public SpongeUser getIfLoaded(UserIdentifier id) {
return this.objects.getIfPresent(id);
}
@Override
public boolean isLoaded(UserIdentifier id) {
return this.objects.asMap().containsKey(id);
}
@Override
public void unload(UserIdentifier id) {
if (id != null) {
this.objects.invalidate(id);
}
}
@Override
public void unload(User t) {
if (t != null) {
unload(t.getId());
}
}
@Override
public void unloadAll() {
this.objects.invalidateAll();
}
/* ------------------------------------------
* UserManager methods
* ------------------------------------------ */
@Override
public SpongeUser getByUsername(String name) {
for (SpongeUser user : getAll().values()) {
Optional<String> n = user.getName();
if (n.isPresent() && n.get().equalsIgnoreCase(name)) {
return user;
}
}
return null;
}
@Override
public SpongeUser getIfLoaded(UUID uuid) {
return getIfLoaded(UserIdentifier.of(uuid, null));
}
@Override
public boolean giveDefaultIfNeeded(User user, boolean save) {
return GenericUserManager.giveDefaultIfNeeded(user, save, this.plugin);
}
@Override
public boolean cleanup(User user) {
// Do nothing - this instance uses other means in order to cleanup
return false;
}
@Override
public void scheduleUnload(UUID uuid) {
// Do nothing - this instance uses other means in order to cleanup
}
@Override
public CompletableFuture<Void> updateAllUsers() {
return CompletableFuture.runAsync(
() -> this.plugin.getOnlinePlayers()
.map(u -> this.plugin.getUuidCache().getUUID(u))
.forEach(u -> this.plugin.getStorage().loadUser(u, null).join()),
this.plugin.getScheduler().async()
);
}
/* ------------------------------------------
* SubjectCollection methods
* ------------------------------------------ */
@Override
public synchronized SubjectCollection sponge() {
if (this.spongeProxy == null) {
@@ -216,6 +117,10 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
return this.spongeProxy;
}
public LPSpongePlugin getPlugin() {
return this.plugin;
}
@Override
public LuckPermsService getService() {
return this.plugin.getService();
@@ -358,7 +263,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
@Override
public ImmutableMap<LPSubject, Boolean> getLoadedWithPermission(String permission) {
return this.objects.asMap().values().stream()
return getAll().values().stream()
.map(SpongeUser::sponge)
.map(sub -> Maps.immutableEntry(sub, sub.getPermissionValue(ImmutableContextSet.empty(), permission)))
.filter(pair -> pair.getValue() != Tristate.UNDEFINED)
@@ -367,7 +272,7 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
@Override
public ImmutableMap<LPSubject, Boolean> getLoadedWithPermission(ImmutableContextSet contexts, String permission) {
return this.objects.asMap().values().stream()
return getAll().values().stream()
.map(SpongeUser::sponge)
.map(sub -> Maps.immutableEntry(sub, sub.getPermissionValue(contexts, permission)))
.filter(pair -> pair.getValue() != Tristate.UNDEFINED)
@@ -379,8 +284,4 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
return getService().getDefaultSubjects().loadSubject(getIdentifier()).join();
}
public LPSpongePlugin getPlugin() {
return this.plugin;
}
}