Fix NPEs caused by RepeatingTask initialisation race condition

This commit is contained in:
Luck 2019-12-26 20:25:14 +00:00
parent 0e64b61be4
commit 10680668db
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
4 changed files with 30 additions and 73 deletions

View File

@ -206,8 +206,8 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
public final void disable() { public final void disable() {
// shutdown permission vault and verbose handler tasks // shutdown permission vault and verbose handler tasks
this.permissionRegistry.stop(); this.permissionRegistry.close();
this.verboseHandler.stop(); this.verboseHandler.close();
// unload extensions // unload extensions
this.extensionManager.close(); this.extensionManager.close();

View File

@ -28,8 +28,8 @@ package me.lucko.luckperms.common.treeview;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
import me.lucko.luckperms.common.util.ImmutableCollectors; import me.lucko.luckperms.common.util.ImmutableCollectors;
import me.lucko.luckperms.common.util.RepeatingTask;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -40,19 +40,20 @@ import java.util.concurrent.TimeUnit;
/** /**
* Stores a collection of all permissions known to the platform. * Stores a collection of all permissions known to the platform.
*/ */
public class PermissionRegistry extends RepeatingTask { public class PermissionRegistry implements AutoCloseable {
private static final Splitter DOT_SPLIT = Splitter.on('.').omitEmptyStrings(); private static final Splitter DOT_SPLIT = Splitter.on('.').omitEmptyStrings();
// the root node in the tree /** The root node in the tree */
private final TreeNode rootNode; private final TreeNode rootNode;
/** A queue of permission strings to be added to the tree */
// a queue of permission strings to be processed by the tree
private final Queue<String> queue; private final Queue<String> queue;
/** The tick task */
private final SchedulerTask task;
public PermissionRegistry(SchedulerAdapter scheduler) { public PermissionRegistry(SchedulerAdapter scheduler) {
super(scheduler, 1, TimeUnit.SECONDS);
this.rootNode = new TreeNode(); this.rootNode = new TreeNode();
this.queue = new ConcurrentLinkedQueue<>(); this.queue = new ConcurrentLinkedQueue<>();
this.task = scheduler.asyncRepeating(this::tick, 1, TimeUnit.SECONDS);
} }
public TreeNode getRootNode() { public TreeNode getRootNode() {
@ -70,13 +71,17 @@ public class PermissionRegistry extends RepeatingTask {
this.queue.offer(permission); this.queue.offer(permission);
} }
@Override private void tick() {
protected void tick() {
for (String e; (e = this.queue.poll()) != null; ) { for (String e; (e = this.queue.poll()) != null; ) {
insert(e); insert(e);
} }
} }
@Override
public void close() {
this.task.cancel();
}
public void insert(String permission) { public void insert(String permission) {
try { try {
doInsert(permission); doInsert(permission);

View File

@ -1,53 +0,0 @@
/*
* 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.util;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
import java.util.concurrent.TimeUnit;
public abstract class RepeatingTask {
private final SchedulerTask task;
protected RepeatingTask(SchedulerAdapter scheduler, long time, TimeUnit unit) {
this.task = scheduler.asyncRepeating(this::run, time, unit);
}
private void run() {
try {
tick();
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract void tick();
public void stop() {
this.task.cancel();
}
}

View File

@ -27,8 +27,8 @@ package me.lucko.luckperms.common.verbose;
import me.lucko.luckperms.common.calculator.result.TristateResult; import me.lucko.luckperms.common.calculator.result.TristateResult;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter; import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
import me.lucko.luckperms.common.sender.Sender; import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.RepeatingTask;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent; import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent; import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import me.lucko.luckperms.common.verbose.event.VerboseEvent; import me.lucko.luckperms.common.verbose.event.VerboseEvent;
@ -45,21 +45,21 @@ import java.util.concurrent.TimeUnit;
/** /**
* Accepts {@link VerboseEvent}s and passes them onto registered {@link VerboseListener}s. * Accepts {@link VerboseEvent}s and passes them onto registered {@link VerboseListener}s.
*/ */
public class VerboseHandler extends RepeatingTask { public class VerboseHandler implements AutoCloseable {
// the listeners currently registered /** A map of currently registered listeners */
private final Map<UUID, VerboseListener> listeners; private final Map<UUID, VerboseListener> listeners;
/** A queue of verbose events to be handled */
// a queue of events
private final Queue<VerboseEvent> queue; private final Queue<VerboseEvent> queue;
/** If there are any listeners registered */
// if there are any listeners currently registered
private boolean listening = false; private boolean listening = false;
/** The tick task */
private final SchedulerTask task;
public VerboseHandler(SchedulerAdapter scheduler) { public VerboseHandler(SchedulerAdapter scheduler) {
super(scheduler, 100, TimeUnit.MILLISECONDS);
this.listeners = new ConcurrentHashMap<>(); this.listeners = new ConcurrentHashMap<>();
this.queue = new ConcurrentLinkedQueue<>(); this.queue = new ConcurrentLinkedQueue<>();
this.task = scheduler.asyncRepeating(this::tick, 100, TimeUnit.MILLISECONDS);
} }
/** /**
@ -137,8 +137,7 @@ public class VerboseHandler extends RepeatingTask {
return this.listeners.remove(uuid); return this.listeners.remove(uuid);
} }
@Override private void tick() {
protected void tick() {
// remove listeners where the sender is no longer valid // remove listeners where the sender is no longer valid
this.listeners.values().removeIf(l -> !l.getNotifiedSender().isValid()); this.listeners.values().removeIf(l -> !l.getNotifiedSender().isValid());
@ -159,4 +158,10 @@ public class VerboseHandler extends RepeatingTask {
} }
} }
} }
@Override
public void close() {
this.task.cancel();
}
} }